青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

搜索題的調試技巧以及一些附加內容

Posted on 2012-03-22 20:49 Mato_No1 閱讀(718) 評論(1)  編輯 收藏 引用 所屬分類: 搜索
【背景(神犇不要鄙視)】
本沙茶在搜索題目的調試上已經掛過兩次了(NOI2011的game用了2h+木有調出來,還耽誤了繼續想show的時間,結果被擋在了集訓隊門外;NOIP2011的mayan,用暴搜都調了2h+,木有調出來,結果慘掛,全國第200名,如果這題AC了就是全國前50名……),為了防止在接下來的比賽中再在這里掛掉,本沙茶決定好好搞一下這個。

【DFS的調試技巧】
如果決定一道題用DFS捉,那么:
(1)如果能套經典模型(當然本沙茶目前只會一個經典模型:DLX),就寫經典模型(DLX應該不會寫疵的,即使疵了,也很容易調試的囧)
(2)如果不能,上來先寫暴搜,并命名為0號版本;
(3)i號版本調試正確之后,再去加剪枝,每次只加一個剪枝(如果時間來不及了,就按照由強到弱或者由好寫到難寫的順序來),調對了再加下一個,每加一個都開一個新的版本;
(4)調試時,如果出現的是RE或者死循環,就在出錯的狀態處停止,并檢查其所有的祖先狀態(顯然這需要記下每次的決策),看看這些決策是否合法;
(5)如果程序正常結束,但結果錯誤,又分為以下3種情況:
<1>明明有解,輸出無解:可以把正解的各個決策一步一步代入,看看程序里面是在哪一步出了問題(明明合法的決策它木有作出),從而方便檢查;
<2>輸出不合法的解:可以把形成這個不合法解的決策一步一步代入,看看是哪一步出了問題;
<3>輸出合法但非最優的解:必然是某些最優性剪枝錯誤或者最優性判斷出了問題,可以直接到這些地方去檢查,實在不行也可以把最優解代入檢查;
(6)當然,在動態查錯之前,要認真地讀一遍代碼;
(7)有時也可以用分段檢查的方法,即把代碼中的各個過程或者片段截取下來,將幾組小的輸入代入,看看執行之后,所有在該片段里改變了值的全局變量是否正確,進而發現這里的錯誤;
(8)千萬不要一下子輸出全部的狀態!本沙茶在比賽中用的就是這種辦法,結果不僅木有查出來,還把自己繞暈掉了,最后時間到了連刪printf的時間都木有……事實上,只有在狀態總數不太多,且相對關系明了、順序整齊的時候(比如一般的DP等),可以一下子輸出全部狀態來檢查,否則就不能這么搞;

【BFS的調試技巧】
BFS其實是比DFS要好調得多,因為所有的狀態都儲存在隊列里,因此,可以在狀態結點中記下每個點的FA(前趨狀態),然后,哪里出了問題,就把前趨狀態全部搞出來即可,另外,BFS一般木有“剪枝”這一說(除了判重),且決策過程一般是比較整齊的,因此好調;

【例題】
(1)NOIP2011 mayan(無比痛苦的回憶啊啊……)
不用信WJMZBMR的題解(什么“最小表示法”……),這題其實不用加過多剪枝,只需要加以下2個剪枝即可:
<1>如果某種顏色只剩下1或2個,剪枝;
<2>(這個其實不是剪枝)在決策的時候,對于兩個相鄰的方塊,把左邊的往右移與把右邊的往左移是等價的,又因為往右移優先,所以在枚舉決策的時候,除非某方塊左邊是空格,否則不要把它往左移;
本題主要是在移動后的消去處理過程(sol0)中比較容易出問題,因此對于這里重點查一下即可,此外,字典序是按照先列后行再移動方向的順序進行的,不要搞疵;
代碼(RQNOJ實測結果:最慢的點1.2s左右):
#include <iostream>
#include 
<stdio.h>
#include 
<stdlib.h>
#include 
<string.h>
using namespace std;
#define re(i, n) for (int i=0; i<n; i++)
#define re1(i, n) for (int i=1; i<=n; i++)
#define re2(i, l, r) for (int i=l; i<r; i++)
#define re3(i, l, r) for (int i=l; i<=r; i++)
#define rre(i, n) for (int i=n-1; i>=0; i--)
#define rre1(i, n) for (int i=n; i>0; i--)
#define rre2(i, r, l) for (int i=r-1; i>=l; i--)
#define rre3(i, r, l) for (int i=r; i>=l; i--)
#define ll long long
const int n = 7, m = 5, MAXC = 11, MAXP = 5, INF = ~0U >> 2;
int P, A[n][m], s[MAXP][3], res[MAXP][3], T[n], sum[MAXC];
bool B[n][m], res_ex = 0;
void init()
{
    freopen(
"mayan.in""r", stdin);
    scanf(
"%d"&P); int x, len;
    re(i, m) {len 
= 0while (1) {scanf("%d"&x); if (x) A[len++][i] = x; else break;}}
    fclose(stdin);
}
bool sol0()
{
    re(i, n) re(j, m) B[i][j] 
= 0;
    
int x, len;
    re(i, n) re2(j, 
2, m) if (A[i][j] && A[i][j] == A[i][j - 1&& A[i][j] == A[i][j - 2]) {
        B[i][j] 
= B[i][j - 1= B[i][j - 2= 1; x = j - 3;
        
while (x >= 0 && A[i][j] == A[i][x]) x--;
        re2(k, x
+1, j-2) B[i][k] = 1;
    }
    re(j, m) re2(i, 
2, n) if (A[i][j] && A[i][j] == A[i - 1][j] && A[i][j] == A[i - 2][j]) {
        B[i][j] 
= B[i - 1][j] = B[i - 2][j] = 1; x = i - 3;
        
while (x >= 0 && A[i][j] == A[x][j]) x--;
        re2(k, x
+1, i-2) B[k][j] = 1;
    }
    
bool FF = 0; re(i, n) re(j, m) if (B[i][j]) {FF = 1; A[i][j] = 0;}
    
if (FF) {
        re(j, m) {
            len 
= 0; re(i, n) if (A[i][j]) {T[len++= A[i][j]; A[i][j] = 0;}
            re(i, len) A[i][j] 
= T[i];
        }
    }
    
return FF;
}
void solve(int v)
{
    
if (v == P) {
        re(i, m) 
if (A[0][i]) return;
        res_ex 
= 1; re(i, P) re(j, 3) res[i][j] = s[i][j];
    } 
else {
        re(i, MAXC) sum[i] 
= 0;
        re(i, n) re(j, m) sum[A[i][j]]
++;
        re2(i, 
1, MAXC) if (sum[i] == 1 || sum[i] == 2return;
        
int tmp, len, A0[n][m];
        re(i, n) re(j, m) A0[i][j] 
= A[i][j];
        re(j, m) re(i, n) 
if (A[i][j]) {
            
if (j < m - 1) {
                tmp 
= A[i][j]; A[i][j] = A[i][j + 1]; A[i][j + 1= tmp;
                re(j0, m) {
                    len 
= 0; re(i0, n) if (A[i0][j0]) {T[len++= A[i0][j0]; A[i0][j0] = 0;}
                    re(i0, len) A[i0][j0] 
= T[i0];
                }
                
while (sol0()) ;
                s[v][
0= j; s[v][1= i; s[v][2= 1;
                solve(v 
+ 1); if (res_ex) return;
                re(i0, n) re(j0, m) A[i0][j0] 
= A0[i0][j0];
            }
            
if (j && !A[i][j - 1]) {
                tmp 
= A[i][j]; A[i][j] = A[i][j - 1]; A[i][j - 1= tmp;
                re(j0, m) {
                    len 
= 0; re(i0, n) if (A[i0][j0]) {T[len++= A[i0][j0]; A[i0][j0] = 0;}
                    re(i0, len) A[i0][j0] 
= T[i0];
                }
                
while (sol0()) ;
                s[v][
0= j; s[v][1= i; s[v][2= -1;
                solve(v 
+ 1); if (res_ex) return;
                re(i0, n) re(j0, m) A[i0][j0] 
= A0[i0][j0];
            }
        }
    }
}
void pri()
{
    freopen(
"mayan.out""w", stdout);
    
if (res_ex) re(i, P) printf("%d %d %d\n", res[i][0], res[i][1], res[i][2]); else printf("%d\n"-1);
    fclose(stdout);
}
int main()
{
    init();
    solve(
0);
    pri();
    
return 0;
}

(2) 小木棍(整數分組模型)
經典的DFS剪枝題。需要很多很強的剪枝:
<1>枚舉最后形成木棍(以下簡稱大木棍)的長度P的時候有限制,這個就不說了;
<2>所有相同長度的木棍都要合并,最終所有木棍按照長度遞減存在數組里面,在枚舉的時候只需枚舉這個木棍使用的個數,且從大到小枚舉;
<3>為了減少枚舉量,要用Dancing Link優化;
<4>很顯然,枚舉每根大木棍的時候,目前剩下的最長的木棍肯定要至少使用一次,且如果該長度的木棍使用了K次,則以后的所有大木棍都最多只能使用K次(除非該長度的木棍被用完了),這是用字典序保證不重復枚舉;
<5>要加上一個強剪枝:如果目前加上一個(只能一個)長度為L的木棍以后,恰好拼成一個完整的大木棍,但是之后失敗了,此時就不用再枚舉接下來更短的木棍了,因為如果用它們得到了解,則把它們與一個長度L的木棍交換也是可行解;
<6>只要倒數第2根大木棍拼成了,就找到了解,因為剩下的肯定能拼成最后一根;
由于這題的剪枝很多,很繁瑣,極易出錯,因此寫的時候要非常小心,查錯也很麻煩囧……

代碼(PKU上0ms,UVA上144ms):
#include <iostream>
#include 
<stdio.h>
#include 
<stdlib.h>
#include 
<string.h>
using namespace std;
#define re(i, n) for (int i=0; i<n; i++)
#define re1(i, n) for (int i=1; i<=n; i++)
#define re2(i, l, r) for (int i=l; i<r; i++)
#define re3(i, l, r) for (int i=l; i<=r; i++)
#define rre(i, n) for (int i=n-1; i>=0; i--)
#define rre1(i, n) for (int i=n; i>0; i--)
#define rre2(i, r, l) for (int i=r-1; i>=l; i--)
#define rre3(i, r, l) for (int i=r; i>=l; i--)
#define ll long long
const int n = 50, INF = ~0U >> 2;
int P, P0, A[n + 1], L[n + 1], R[n + 1];
bool res_ex;
void prepare()
{
    L[
0= R[0= 0; re1(i, n) if (A[i]) {L[i] = L[0]; R[i] = 0; L[0= i; R[L[i]] = i;}
}
void solve(int dep, int len, int K, int x1)
{
    
if (dep == P0) res_ex = 1else {
        
int len0, s0;
        
if (len == P) {
            
int maxv = L[0];
            s0 
= len / maxv <= A[maxv] ? len / maxv : A[maxv]; if (s0 > x1) s0 = x1;
            len0 
= len - (s0 + 1* maxv;
            rre1(i, s0) {
                
if ((P0 - dep + 1* i < A[maxv]) return;
                A[maxv] 
-= i; if (!A[maxv]) {L[R[maxv]] = L[maxv]; R[L[maxv]] = R[maxv];} len0 += maxv;
                
if (len0) solve(dep, len0, L[maxv], A[maxv] ? i : INF); else {
                    solve(dep 
+ 1, P, 0, x1);
                    
if (i == 1 && !res_ex) {
                        
if (!A[maxv]) L[R[maxv]] = R[L[maxv]] = maxv;
                        A[maxv] 
+= i; return;
                    }
                }
                
if (res_ex) return;
                
if (!A[maxv]) L[R[maxv]] = R[L[maxv]] = maxv; A[maxv] += i;
            }
        } 
else {
            
int i = K;
            
while (i) {
                
if (A[i] && i <= len) {
                    s0 
= len / i <= A[i] ? len / i : A[i];
                    len0 
= len - (s0 + 1* i;
                    rre1(j, s0) {
                        A[i] 
-= j; if (!A[i]) {L[R[i]] = L[i]; R[L[i]] = R[i];} len0 += i;
                        
if (len0) solve(dep, len0, L[i], x1); else {
                            solve(dep 
+ 1, P, 0, x1);
                            
if (j == 1 && !res_ex) {
                                
if (!A[i]) L[R[i]] = R[L[i]] = i;
                                A[i] 
+= j; return;
                            }
                        }
                        
if (res_ex) return;
                        
if (!A[i]) L[R[i]] = R[L[i]] = i; A[i] += j;
                    }
                }
                i 
= L[i];
            }
        }
    }
}
int main()
{
    
int n0, x, sum, maxv;
    
while (1) {
        scanf(
"%d"&n0); if (!n0) breakelse {sum = 0; maxv = 0; re1(i, n) A[i] = 0; res_ex = 0;}
        re(i, n0) {scanf(
"%d"&x); A[x]++; sum += x; if (x > maxv) maxv = x;} prepare();
        re3(i, maxv, sum) 
if (!(sum % i)) {
            P 
= i; P0 = sum / i - 1; solve(0, P, 0, INF);
            
if (res_ex) {printf("%d\n", i); break;}
        }
    }
    
return 0;
}

【附加內容】
在mayan的代碼中有一個數組A0,用于在過程中備份A數組,使得它在下面搜索失敗之后能及時更新(因為這里的A經歷了sol0處理,更新比較麻煩),這種備份數組在很多題里面都有應用,不過要注意,這個數組一定要寫成局部的,不能寫成全局的!!(本沙茶在比賽的時候就是寫成全局的了,結果導致出錯查不出來的……)如果怕寫成局部的MLE,也可以寫成全局的,但是要分層,即對于每個搜索深度(v、dep等變量控制),要開專門的一層,保證搜索過程中各層不互相覆蓋。

Feedback

# re: 搜索題的調試技巧以及一些附加內容  回復  更多評論   

2012-03-25 20:57 by 淺棲
2011NOIP參加過的握手。。。想去年我也是暴搜調了不知道多久,最后差點就放棄了。。。
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲国产日韩一区| 亚洲一区二区成人在线观看| 亚洲人成在线观看一区二区| 在线观看一区二区视频| 亚洲二区在线视频| 亚洲欧洲免费视频| 亚洲视频在线一区观看| 亚洲欧美视频在线| 欧美在线国产| 乱人伦精品视频在线观看| 亚洲福利视频网站| 亚洲人成亚洲人成在线观看| avtt综合网| 欧美自拍偷拍| 欧美精品一区二区精品网| 欧美性理论片在线观看片免费| 国产精品揄拍一区二区| 影音国产精品| 亚洲综合首页| 久久视频国产精品免费视频在线| 亚洲第一狼人社区| 在线亚洲美日韩| 久色成人在线| 国产目拍亚洲精品99久久精品| 狠狠狠色丁香婷婷综合久久五月| 一本不卡影院| 免费成人黄色av| 亚洲天堂av电影| 免费欧美电影| 国产一区视频在线观看免费| 亚洲作爱视频| 免费不卡在线观看| 午夜精品一区二区三区在线| 欧美—级a级欧美特级ar全黄| 国产综合自拍| 亚洲在线视频| 亚洲日本中文字幕免费在线不卡| 久久av一区二区三区| 国产精品xnxxcom| 亚洲片在线资源| 免费成人av资源网| 欧美一区二区久久久| 欧美猛交免费看| 亚洲精品麻豆| 欧美大香线蕉线伊人久久国产精品| 亚洲欧美日韩网| 欧美视频网址| 亚洲午夜精品一区二区三区他趣| 亚洲国产成人精品久久久国产成人一区 | 亚洲欧美一区二区三区极速播放| 欧美呦呦网站| 日韩一级在线观看| 欧美激情1区2区| 亚洲国产精品尤物yw在线观看| 欧美综合国产精品久久丁香| 亚洲视频一区| 国产精品一区久久| 午夜激情综合网| 一区二区三区日韩精品| 欧美日韩精品在线视频| 一区二区欧美亚洲| 在线视频免费在线观看一区二区| 欧美日韩一区二区在线播放| av成人免费观看| 日韩视频一区二区| 欧美视频精品一区| 午夜精品久久久久久久蜜桃app| 亚洲欧美日韩国产成人| 国产色婷婷国产综合在线理论片a| 欧美一二三区精品| 欧美有码视频| 在线欧美影院| 亚洲激情黄色| 欧美色播在线播放| 午夜久久福利| 香蕉久久夜色精品国产| 国产一区二区三区无遮挡| 蜜乳av另类精品一区二区| 久久久999精品免费| 亚洲靠逼com| 亚洲一区欧美激情| 国产自产精品| 亚洲高清在线观看一区| 欧美日韩高清免费| 久久av二区| 免费欧美在线| 欧美一级黄色录像| 欧美ed2k| 欧美一区二区三区久久精品| 久久精品在线播放| 99国产精品久久久久久久久久| 日韩一区二区福利| 国产主播在线一区| 亚洲国产视频一区二区| 国产精品网站视频| 亚洲第一视频| 国产精品美女久久久浪潮软件 | 在线观看亚洲一区| 亚洲美女免费精品视频在线观看| 国产毛片一区二区| 欧美激情一二三区| 国产欧美精品xxxx另类| 亚洲人体1000| 亚洲国产精品成人一区二区 | 亚洲一区二区在线免费观看视频 | 欧美精品情趣视频| 亚洲午夜久久久| 久久久久久香蕉网| 亚洲尤物影院| 麻豆国产精品777777在线| 欧美一级一区| 欧美日韩国产色综合一二三四| 久久精品国产一区二区电影 | 亚洲国产精品久久久久婷婷884| 国产精品一区二区三区久久久| 亚洲高清资源综合久久精品| 国产欧美日韩视频一区二区| 亚洲精品乱码久久久久久蜜桃麻豆 | 久久久久久久久岛国免费| 亚洲在线免费观看| 欧美日韩国产在线播放网站| 欧美96在线丨欧| 国产亚洲一区二区三区| 亚洲素人一区二区| 亚洲一区二区欧美日韩| 欧美激情视频一区二区三区免费| 久久婷婷一区| 国产亚洲精品bt天堂精选| 亚洲午夜视频| 亚洲欧美在线看| 亚洲一区美女视频在线观看免费| 一区二区欧美亚洲| 欧美午夜宅男影院| 亚洲一区不卡| 亚洲欧美清纯在线制服| 国产精品大片wwwwww| 这里只有精品视频| 亚洲欧美日韩在线播放| 国产精品久久久久天堂| 亚洲女性裸体视频| 久久九九免费视频| 在线观看国产日韩| 久久亚洲私人国产精品va| 欧美大秀在线观看| 亚洲另类视频| 欧美日韩国产一区二区三区地区| 亚洲第一色中文字幕| 99国产精品国产精品毛片| 欧美日韩另类国产亚洲欧美一级| 亚洲精品久久在线| 香蕉成人伊视频在线观看 | 亚洲影视九九影院在线观看| 亚洲资源av| 国产亚洲一区在线播放| 久久久精品性| 亚洲黄色天堂| 亚洲一二三级电影| 国产视频在线观看一区二区| 久久婷婷国产综合尤物精品 | 久久视频一区二区| 亚洲人成小说网站色在线| 欧美电影在线播放| 亚洲经典视频在线观看| 欧美激情综合色| 亚洲欧美卡通另类91av| 欧美1区视频| 夜夜嗨av色综合久久久综合网| 欧美日韩第一区| 欧美影院成人| 亚洲美洲欧洲综合国产一区| 久久精品免费观看| 99www免费人成精品| 国产免费亚洲高清| 欧美精品久久久久久久久久| 亚洲在线观看免费视频| 欧美国产日韩一区二区三区| 亚洲综合首页| 亚洲精品久久7777| 国产亚洲精品v| 欧美三日本三级三级在线播放| 久久久91精品| 亚洲一区日本| 亚洲精品乱码久久久久久黑人| 久久久噜噜噜久久狠狠50岁| 亚洲午夜视频在线| 亚洲激情国产| 一区在线播放| 国产色产综合色产在线视频| 欧美精品一线| 美女999久久久精品视频| 亚洲欧美网站| 亚洲一区二区三区乱码aⅴ蜜桃女| 欧美第十八页| 美女亚洲精品| 久久久久网址| 性欧美xxxx大乳国产app| 亚洲少妇在线| 亚洲视频一区二区| 在线亚洲观看| 一区二区欧美日韩|