### 【ACM算法回顧】簡單搜索

• 今天主要回顧一下幾個搜索
• DFS  ——Depth First Search
• A*
• 迭代加深搜索

` 1 def A_star_search 2     q = PriorityQueue() 3     #優先隊列，順便起到open表的作用 4     q.put(qnode) 5     came_from = {} 6     #came_from為記錄拓展過程的鏈表 7     cost_so_far = {} 8     #cost_so_far[p]為起點到節點p目前已知花費 9     came_from[start_state] = None10     cost_so_far[start_state] = 011 12     while not q.empty():13         cur_state = q.get()14         if cur_state == goal_state:15             break16         #假設用鄰接表存儲，用邊權矩陣原理類似17         for nxt in G.neighbour(cur_state):18             new_cost = cost_so_far[cur_state] + G.cost(cur_state, nxt)19             if nxt not in cost_so_far or new_cost < cost_so_far[nxt]20                 cost_so_far[nxt] = new_cost21                 priority = new_cost + heuristic(goal_state, nxt)22                 q.put(qnode(....including "priority", "nxt"))23                 came_from[nxt] = cur_state24 25     return came_from, cost_so_far`

DFS和BFS都不在乎邊權，而都是以層次為划分進行搜索，DFS的搜索順序是深層節點優先，BFS的搜索順序是同層節點優先

A-棋盤問題（poj 1321）

就是在給定形狀的棋盤上問有多少種方式可以不同行不同列地擺放棋子

枚舉每個可擺放區域擺或不擺即可

` 1 #include<cstdio> 2 #include<algorithm>  3 #include<cstring> 4 using namespace std; 5  6 const int N = 10; 7  8 struct node{ 9     node(){}10     node(int x_, int y_){11         x=x_;12         y=y_;13     }14     int x,y;15 }D[N];16 int k,n,cnt,ans;17 bool use[N];18 19 bool cmp(node a,node b)20 {21     return a.x<b.x;22 }23 24 void dfs(int i, int step)25 {26     if(step == k)27     {28         ans++;29         return;30     }31     use[D[i].y] = 1;32     for(int t=i+1; t<=cnt-k+1+step; t++)33     {34         if(use[D[t].y]||D[t].x == D[i].x) continue;35         dfs(t, step+1);36     }37     use[D[i].y] = 0;38 }39 40 int main()41 {42     freopen("poj1321.in","r",stdin);43     44     char ch;45     46     while(1)47     {48         cnt = 0;49         ans = 0;50         memset(use,0,sizeof(use));51         52         scanf("%d %d", &n, &k);53         if(n==-1 && k==-1) break;54         for(int i=1;i<=n;i++)55         for(int j=1;j<=n;j++)56         {57             scanf(" %c",&ch);58             if(ch == '#') D[++cnt]=node(i,j);59         }60         sort(D+1,D+cnt+1,cmp);61         for(int i=1; i<=cnt-k+1; i++) dfs(i,1);62         printf("%d\n",ans);63     } 64     return 0;65 } `

B-Dungeon Master （poj 2251）

給定一個3D的監獄地圖，問你有沒有辦法逃出來，如果有，問最短路徑

很基礎的BFS

` 1 /* 2     L level 3     R row 4     C colomn 5 */ 6  7 #include<cstdio> 8 #include<cstring> 9 #include<queue>10 using namespace std;11 12 const int N = 30 + 5;13 int ans;14 int map[N][N][N];15 int l,r,c;16 int sl,sr,sc;17 int tl,tr,tc;18 int u[6]={ 1,-1, 0, 0, 0, 0};19 int v[6]={ 0, 0, 1,-1, 0, 0};20 int w[6]={ 0, 0, 0, 0, 1,-1};21 bool inq[N][N][N];22 struct qnode{23     qnode(){}24     qnode(int _l,int _r,int _c,int _step)25     {26         l = _l; r = _r; c = _c; step = _step;27     }28     int l,r,c,step;29 };30 31 void bfs()32 {33     queue <qnode> q;34     int curl,curr,curc;35     int dl,dr,dc;36     37     q.push(qnode(sl,sr,sc,0));38     inq[sl][sr][sc]=1;39     while(!q.empty())40     {41         qnode cur = q.front();42         q.pop();43         for(int i=0;i<6;i++)44         {45             dl = cur.l + u[i];46             dr = cur.r + v[i];47             dc = cur.c + w[i];48             if (dl<1 || dl>l || dr<1 || dr>r || dc<1 || dc>c) continue;49             if (!map[dl][dr][dc]) continue;50             if (dl == tl && dr == tr && dc == tc)51             {52                 ans = cur.step + 1;53                 return;54             }55             if (!inq[dl][dr][dc])56             {57                 inq[dl][dr][dc] = 1;58                 q.push(qnode(dl,dr,dc,cur.step+1));59             }60         }61     }62 }63 64 int main()65 {66     #ifndef ONLINE_JUDGE67         freopen("poj2251.in","r",stdin);68     #endif69     char ch;70     71     while(1)72     {73         memset(inq,0,sizeof(inq));74         memset(map, 0, sizeof(map));75         ans = -1;76         77         scanf("%d %d %d",&l,&r,&c);78         if(l==0 && r==0 && c==0) break;79         for(int i=1;i<=l;i++)80         for(int j=1;j<=r;j++)81         for(int k=1;k<=c;k++)82         {83             scanf(" %c",&ch);84             if(ch != '#') map[i][j][k] = 1;85             if(ch == 'S') sl=i,sr=j,sc=k;86             if(ch == 'E') tl=i,tr=j,tc=k; 87         }88         bfs();89         if (ans!=-1)90             printf("Escaped in %d minute(s).\n",ans);91         else printf("Trapped!\n");92     }93     return 0;94 } `

C-Catch that cow（poj 3278）

數軸上有兩個點分別為n,k

有兩種操作，當前坐標加一減一，或者坐標乘二，都耗費一單位時間

求耗費最少的時間是多少

枚舉每一個時間的操作進行BFS

` 1 #include<cstdio> 2 #include<queue> 3 #include<cstring> 4 using namespace std; 5  6 const int N = 100000 + 10; 7  8 int n,k; 9 int ans;10 int f[N];11 struct qnode{12     qnode(){}13     qnode(int _n,int _step){14         n=_n; step=_step;15     }16     int n,step;17 };18 19 void bfs()20 {21     memset(f, -1, sizeof(f));22     23     f[n] = 0;24     queue <qnode> q;25     q.push(qnode(n,0));26     27     while(!q.empty())28     {29         qnode cur = q.front(); q.pop();30         if (cur.n-1>=0 && f[cur.n-1]==-1)31         {32             f[cur.n-1] = cur.step + 1;33             q.push(qnode(cur.n-1, cur.step + 1));34         }35         if (cur.n+1<=k && f[cur.n+1]==-1)36         {37             f[cur.n+1] = cur.step + 1;38             q.push(qnode(cur.n+1, cur.step + 1));39         }40         if (cur.n * 2< N && f[cur.n * 2]==-1)41         {42             f[cur.n*2] = cur.step + 1;43             q.push(qnode(cur.n*2, cur.step + 1));44         }45         if (f[k]!=-1){ans=f[k]; return;}46     }47 }48 49 int main()50 {51     #ifndef ONLINE_JUDGE52         freopen("poj3278.in","r",stdin);53     #endif54     scanf("%d %d",&n,&k);55     if (n<k) bfs();56     else ans = n-k;57     58     printf("%d\n",ans);59     return 0;60 } `

D-Fliptile （poj 3279）

翻動棋盤上的棋子使所有棋子白面朝上，且每次翻動會帶動相鄰的四顆棋子，問翻動方案

乍一看需要枚舉的方案很多，但我們發現當某一行翻動方案確定時，下一行的方案也就確定了

比如某一行在下一行翻動以前狀態為0 0 1 0 那么顯然下一行就應該翻動第3個位置，以此類推，發現真正需要枚舉的只有第一行的翻動方案

`  1 #include<cstdio>  2 #include<cstring>  3   4 const int N = 15+5;  5 const int INF = 0xfffffff;  6   7 int row[N];  8 int maps[N][N];  9 int opt[N][N],ansi; 10 int ans_opt[N][N]; 11 int r,c; 12 int ans=INF; 13  14 void reverse(int *a,int pos) 15 { 16     if(pos-1>=1) a[pos-1]^=1; 17     a[pos]^=1; 18     if(pos+1<=c) a[pos+1]^=1; 19 }  20  21 int main() 22 { 23     #ifndef ONLINE_JUDGE 24         freopen("poj3279.in","r",stdin); 25     #endif 26      27     scanf("%d %d",&r,&c); 28      29     for(int i=1;i<=r;i++) 30     for(int j=1;j<=c;j++) 31         scanf("%d",&maps[i][j]); 32      33     for(int i=0; i< (1<<c); i++) 34     { 35         //枚舉第一行翻動情況 36         memset(opt,0,sizeof(opt)); 37         int cur_ans = 0; 38         int t=i,last_t=0; 39          40         for(int u=1;u<=r;u++) 41         { 42             int cnt=0; 43             for(int v=1;v<=c;v++) row[v]=maps[u][v]; 44              45             //DEBUG 46             //if(i==10) for(int p=1;p<=c;p++) printf("%d ",row[p]); 47              48             while(last_t){ 49                 cnt++; 50                 if (last_t&1) row[cnt] ^= 1; 51                 last_t>>=1; 52             } 53             last_t = t; 54              55             cnt=0; 56             while(t){ 57                 cnt++; 58                 if (t&1) 59                 { 60                     opt[u][cnt] = 1; 61                     cur_ans++; 62                     reverse(row,cnt); 63                 } 64                 t>>=1; 65             } 66             if (cur_ans > ans) break; 67             //check 68             if(u==r) 69             { 70                 int flag = 1; 71                 for(int v=1;v<=c;v++) 72                 if(row[v]) 73                 { 74                     flag=0; 75                     break; 76                 } 77                 if(flag) 78                 { 79                     if(cur_ans<ans) 80                     { 81                         ans = cur_ans; 82                         for(int p=1;p<=r;p++) 83                             for(int q=1;q<=c;q++) 84                                 ans_opt[p][q]=opt[p][q]; 85                     } 86                 } 87             } 88             //由當前行推出下一行翻動狀態 89             t = 0; 90             for(int v=c;v>=1;v--){ 91                 t<<=1; 92                 if (row[v]) t|=1; 93             }  94         } 95     } 96      97     if (ans!=INF) 98         for(int p=1;p<=r;p++) 99         {100             for(int q=1;q<=c;q++) printf("%d ",ans_opt[p][q]);101             printf("\n");102         }103     else printf("IMPOSSIBLE\n");104     return 0;105 }`

E-Find The Multiple（poj 1426）

給定一個數字n，求其倍數m使得每一位只有0和1

第一想法居然是高精度...我真是傻到家了

這里的搜索有點意思，就是枚舉第k位為0或者1時模n的結果，如果為零則為答案

比如k = xxxxxxx （x為0或1）

xxxxxxx1 % n= (10 * k + 1 )%n

xxxxxxx0 % n= (10*k)%n

因此我們可以把這些mod以后的結果保存下來，由小到大遞推

mod_res[xxxxxxx1] = (mod_res[xxxxxxx] * 10 + 1)%n

mod_res[xxxxxxx0] = (mod_res[xxxxxxx] * 10)%n

即可找到答案

然后...200以內打表打法，就不貼了....（丟人