搜索入门_简单搜索bfs dfs大杂烩
dfs题大杂烩
棋盘问题 POJ - 1321
和经典的八皇后问题一样. 给你一个棋盘,只有#区域可以放棋子,同时同一行和同一列只能有一个棋子. 问你放k个棋子有多少种方案.
很明显,这是搜索题.
因为每一行和每一列只能有一个棋子,所以我们可以从第k行一直到第n行枚举所有放棋子的情况,即我们从当前状态(当前行)dfs到第n行.然后符合添加的,我们就ans++.
dfs过程见代码.
#include <cstdio> #include <cstring> int n,k,c,way; // 检查当前棋盘区域是否可以放置棋子 bool isok(char vis[][16],int x,int y) { int i; for(i=0; i<n; ++i) if('V'==vis[x][i]) return false; for(i=0; i<n; ++i) if('V'==vis[i][y]) return false; return true; } void dfs(char vis[16][16],int cnt,int line) { int i,j; char mvis[16][16]; if(k==cnt){ c++; // 走到了末尾 方案加一 return ; }else if(line==n){ return ; }else if(n-line+cnt<k){ //"剪枝" return ; }else{ memcpy(mvis,vis,sizeof(mvis)); //注意sizeof的"陷阱",sizeof(指针)==4,所以不能传sizeof(vis) sizeof(数组名)==数组大小 for(i=line; i<n; ++i){ //注意i=line 而不是0 for(j=0; j<n; ++j){ if('#'==mvis[i][j] && isok(mvis,i,j)){ // 当前坐标是棋盘区域, 同时同一行同一列没有放置棋子 mvis[i][j] = 'V'; // 放棋子 dfs(mvis,cnt+1,i+1); mvis[i][j] = '#'; // 取消放棋子的状态, 继续枚举其他情况 } } } return ; } } int main() { int i,j; char map[16][16]; // freopen("D:\\input.txt","r",stdin); while(scanf("%d%d",&n,&k) && (n!=-1 || k!=-1)){ for(i=0; i<n; ++i){ scanf("%s",map[i]); } c=0; dfs(map,0,0); printf("%d\n",c); } return 0; }
Fliptile POJ - 3279
给你一个0和1组成的矩阵.你可以将某一格子阵翻转.但是你翻转一个格子,他上下左右的格子也会背翻转.
问你最后是否可以全部翻转成0
如果可以输出一个矩阵: 对应01矩阵翻转的次数.要求该答案矩阵的翻转次数最少,同时如果有多个解,输出字典序最小的一个.
如果不可以, 则输出IMPOSSIBLE
首先,我们分析一下, 我们发现,对于一个格子来说,翻转偶数次是没有意义的.翻转奇数次,才会改变状态.
因为对于一个格子,翻转偶数次是没有贡献的,翻转多个奇数次都等价于翻转一次,所以如果格子需要翻转,那么我们翻转一次就够了.
同时,
我们假定从第一行开始考虑, 如果要全部翻转成0, 那么我们当前行的状态将有由下一行同一列的格子翻转来决定.
所以我们不难知道,如果上一行的这个格子是1的话,那么我们当前格子就需要翻转一下. 一直到最后一行翻转完毕,我们最后再判断一下最后一行是否全都是0,就可以确定答案是否存在.
但是,我们这样并不能保证答案最优.. 我们不难发现这种做法依赖于第一行的初始状态. 因为最多只有十列,所以我们不妨把第一行的所有状态都枚举一下,然后都进行答案的查找.
(ps,枚举状态可以用dfs或者二进制. 而我用的dfs搜索过去.)
#include <cstdio> #include <cstring> using namespace std; int _m[24][24]; int _ct[24][24]; int _ans[24][24]; int tmp[24][24]; int n, m; bool ishave; int qstep; int qsz = 1; inline int fff(int val, int mack) { return val ^ (1<<mack); } void dfs(int now, int step) { int i, j; if (now > m) { // 注意,这里需要对矩阵进行操作,但是操作完成后,我们需要把还原原先的矩阵. // 所以我用了一个临时矩阵来保存. memcpy(_ct, _m, sizeof(_ct)); for (i=2; i<=n; ++i) { for (j=1; j<=m; ++j) { if (_m[i-1][j]) { _m[i][j] = !_m[i][j]; _m[i-1][j] = !_m[i-1][j]; _m[i+1][j] = !_m[i+1][j]; _m[i][j-1] = !_m[i][j-1]; _m[i][j+1] = !_m[i][j+1]; tmp[i][j] = 1; step++; } else tmp[i][j] = 0; } } for (i=1; i<=m; ++i) if (_m[n][i]) { // 当前状态不能全部翻转为0 memcpy(_m, _ct, sizeof(_m)); return ; } if (step > qstep) { // 步数判断 memcpy(_m, _ct, sizeof(_m)); return ; } qstep = step; for (i=1; i<=n; ++i) { // 字典序判断, 注意,这个题的字典序是从右到左的. for (j=m; j>=1; --j) { if (tmp[i][j] != _ans[i][j]) goto A; } } A: if (i<=n && tmp[i][j] < _ans[i][j]) { ishave = true; for (i=1; i<=n; ++i) { for (j=1; j<=m; ++j) _ans[i][j] = tmp[i][j]; } } memcpy(_m, _ct, sizeof(_m)); return ; } // 翻转第一行, 记得翻转的同时,周围的格子也会改变. dfs(now+1, step); tmp[1][now] = 1; _m[1][now] = !_m[1][now]; _m[1][now+1] = !_m[1][now+1]; _m[1][now-1] = !_m[1][now-1]; _m[2][now] = !_m[2][now]; dfs(now+1, step+1); tmp[1][now] = 0; _m[1][now] = !_m[1][now]; _m[1][now+1] = !_m[1][now+1]; _m[1][now-1] = !_m[1][now-1]; _m[2][now] = !_m[2][now]; } /* 4 4 1 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 */ int main() { int i, j; while (~scanf("%d%d", &n, &m)) { memset(_ans, 0x3f, sizeof(_ans)); memset(tmp, 0, sizeof(tmp)); int tmp = 0; int data; for (i=1; i<=n; ++i) for (j=1; j<=m; ++j) scanf("%d", &_m[i][j]); ishave = false; qstep = 0x3f3f3f3f; dfs(1, 0); if (ishave) { for (i=1; i<=n; ++i) { printf("%d", _ans[i][1]); for (j=2; j<=m; ++j) printf(" %d", _ans[i][j]); printf("\n"); } } else printf("IMPOSSIBLE\n"); } return 0; }
Find The Multiple POJ - 1426
给你一个数字,要你求出他的倍数,这个倍数由0和1组成.
这个题利用了求模的一个性质 a%mod <==> (b*10+c)%mod 其中 a = b * 10 + c
所以,我们直接暴力搜过去就OK
#include <cstdio> using namespace std; char ans[105]; bool isover; bool dfs(int val, int n, int deep) { if (!val) { ans[deep] = '\0'; return isover = true; } if (isover) return true; if (deep==100) { return false; } ans[deep] = '0'; if (dfs(val*10%n, n, deep+1)) return true; ans[deep] = '1'; if (dfs((val*10+1)%n, n, deep+1)) return true; return false; } int main() { int n; while (scanf("%d", &n) && n) { isover = false; ans[0] = '1'; dfs(1%n, n, 1); printf("%s\n", ans); } return 0; }
Oil Deposits HDU - 1241
简单的求连通块的个数. 八个方向的连通块. 直接dfs
#include <cstdio> #include <cstring> using namespace std; int n, m; char _m[104][104]; bool vis[104][104]; bool dfs(int x, int y) { if (x<0 || y<0 || x==n || y==m || vis[x][y] || _m[x][y]=='*') return false; vis[x][y] = true; dfs(x-1, y); dfs(x+1, y); dfs(x, y-1); dfs(x, y+1); dfs(x-1, y-1); dfs(x-1, y+1); dfs(x+1, y-1); dfs(x+1, y+1); return true; } int main() { int i, j, res; while (scanf("%d%d", &n, &m) && (n || m)) { memset(vis, 0, sizeof(vis)); for (i=0; i<n; ++i) scanf("%s", _m[i]); res = 0; for (i=0; i<n; ++i) for (j=0; j<m; ++j) res += dfs(i, j); printf("%d\n", res); } return 0; }
Beautiful Now HDU - 6351
给你两个数字n和k, 问你数字n的数位经过至多k次交换后的最大值和最小值.
因为可以任意次数的交换,所以我们最多交换k次或者交换n的长度次即交换min(len(n), k). 所以可以直接暴力.
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; char s1[16]; char s2[16]; char ans[16]; int len; void dfs1(int now, int k) { int i; if (k==0 || now==len) { // if (s1[0] == '0') return ; if (strcmp(ans, s1) > 0) strcpy(ans, s1); return ; } if (now == 0) { for (i=now+1; i<len; ++i) { if (s1[i] < s1[now] && s1[i]!='0') { swap(s1[now], s1[i]); dfs1(now + 1, k-1); swap(s1[now], s1[i]); } } } else { for (i=now+1; i<len; ++i) { if (s1[i] < s1[now]) { swap(s1[now], s1[i]); dfs1(now + 1, k-1); swap(s1[now], s1[i]); } } } dfs1(now+1, k); } void dfs2(int now, int k) { int i; if (k==0 || now==len) { // if (s2[0] == '0') return ; if (strcmp(ans, s2) < 0) strcpy(ans, s2); return ; } for (i=now+1; i<len; ++i) { if (s2[i] > s2[now]) { swap(s2[now], s2[i]); dfs2(now + 1, k-1); swap(s2[now], s2[i]); } } dfs2(now+1, k); } int main() { int t, k; scanf("%d", &t); while (t--) { scanf("%s%d", s1, &k); len = strlen(s1); strcpy(s2, s1); strcpy(ans, s1); dfs1(0, min(k, len)); printf("%s ", ans); strcpy(ans, s2); dfs2(0, min(k, len)); printf("%s\n", ans); } return 0; }
和为K的组合 51Nod - 1268
给你n和数字 和一个k,问你从n个数字中选若干个数字,这些数字的和是否为k
因为n最多只有20个.所以直接爆搜.
#include <cstdio> #include <algorithm> using namespace std; int n, k; int arr[32]; bool cmp(const int &a, const int &b) { return a > b; } bool flag = false; bool dfs(int deep, int val) { if (flag) return true; if (val < 0) return false; if (val == 0) return flag=true; if (deep==n-1) { if (val == arr[deep]) return true; else return false; } return dfs(deep+1, val-arr[deep]) || dfs(deep+1, val); } int main() { int sum; while (~scanf("%d%d", &n, &k)) { sum = k; int i; for (i=0; i<n; ++i) { scanf("%d", &arr[i]); sum -= arr[i]; } sort(arr, arr+n, cmp); flag = false; if (sum>0 || !dfs(0, k)) printf("No\n"); else printf("Yes\n"); } return 0; }
BFS大杂烩
Dungeon Master POJ - 2251
给一个起点,一个终点,多个层.问最短路. 直接bfs.
#include <stdio.h> #include <string.h> #include <queue> using namespace std; int l,n,m; char map[31][31][31]; bool vis[31][31][31]; int dir[] = {1,0,-1,0,1}; int updw[] = {-1,1}; typedef struct nobe{ int x; int y; int l; int step; }nobe; int bfs(nobe s) { int i; nobe bb,cc; queue<nobe> q; q.push(s); memset(vis,0,sizeof(vis)); while(!q.empty()){ bb = q.front(); q.pop(); if(bb.x<0 || bb.y<0 || bb.l<0 || bb.x>=n || bb.y>=m || bb.l>=l) continue; if('#' == map[bb.l][bb.x][bb.y]) continue; if('E' == map[bb.l][bb.x][bb.y]) return bb.step; if(vis[bb.l][bb.x][bb.y]) continue; vis[bb.l][bb.x][bb.y] = 1; for(i=0; i<4; ++i){ cc.step = bb.step+1; cc.l = bb.l; cc.x = bb.x+dir[i]; cc.y = bb.y+dir[i+1]; q.push(cc); } for(i=0; i<2; ++i){ cc.step = bb.step+1; cc.l = bb.l + updw[i]; cc.x = bb.x; cc.y = bb.y; q.push(cc); } } return -1; } int main() { int i,j,z,ans; char str[40]; nobe s; while(scanf("%d%d%d",&l,&n,&m) && (l!=0 || n!=0 || m!=0)){ for(z=0; z<l; ++z){ for(i=0; i<n; ++i){ scanf("%s",str); for(j=0; j<m; ++j){ map[z][i][j] = str[j]; if('S'==str[j]){ s.l = z; s.x = i; s.y = j; s.step = 0; } } } } ans = bfs(s); if(-1 == ans){ printf("Trapped!\n"); }else{ printf("Escaped in %d minute(s).\n",ans); } } return 0; }
Catch That Cow POJ - 3278
给两个数st, ed. 问你st经过至少多少次变换后可以到达ed. st有以下变化: st+1, st-1, st*2
还是很裸的bfs.
但是有个坑我很久的地方是: G++会wa,C++可以A...原因我也不清楚.
#include <cstdio> #include <cstring> #include <queue> using namespace std; struct nobe { int x; int step; nobe () {} nobe (int xx, int tt) : x(xx), step(tt) {} }; bool vis[400100]; int bfs(int n, int k) { memset(vis, 0, sizeof(vis)); nobe now(n, 0); queue<nobe> q; q.push(now); while (!q.empty()) { now = q.front(); q.pop(); if (now.x == k) return now.step; if (vis[now.x]) continue; vis[now.x] = true; if (now.x-1>=0 && !vis[now.x-1]) q.push(nobe(now.x-1, now.step+1)); if (now.x+1<400100&& !vis[now.x+1]) q.push(nobe(now.x+1, now.step+1)); if (now.x*2<400100&& !vis[now.x*2]) q.push(nobe(now.x*2, now.step+1)); } } int main() { int n, k; while (~scanf("%d%d", &n, &k)) { if (n>=k) printf("%d\n", n-k); else printf("%d\n", bfs(n, k)); } return 0; }
不过也有一种bfs不会wa的写法...然而原因我也还是不清楚....
#include <cstdio> #include <cstring> #include <queue> using namespace std; struct nobe { int x; int step; nobe () {} nobe (int xx, int tt) : x(xx), step(tt) {} }; int vis[200100]; int bfs(int n, int k) { memset(vis, 0x3f, sizeof(vis)); nobe now(n, 0); queue<nobe> q; q.push(now); while (!q.empty()) { now = q.front(); q.pop(); if (now.x == k) return now.step; if (vis[now.x] < now.step) continue; vis[now.x] = now.step; if (now.x-1>=0) q.push(nobe(now.x-1, now.step+1)); if (now.x+1<200100) q.push(nobe(now.x+1, now.step+1)); if (now.x*2<200100) q.push(nobe(now.x*2, now.step+1)); } return -1; } int main() { int n, k; while (~scanf("%d%d", &n, &k)) { printf("%d\n", bfs(n, k)); } return 0; }
然后这道题也可以dp做 ---> 因为st-1可能会影响到要更新的dp答案..所以可以暴力点....多做几次dp..多做几十次dp..最后答案就趋近于正确答案了...
当然, 也有别的优秀dp. 但是我不会.
Prime Path POJ - 3126
题目我忘记了. 代码也是copy的以前的. 所以直接粘上来.
#include <cstdio> #include <iostream> #include <set> #include <map> #include <queue> #include <cstring> using namespace std; bool isprime[10000]; void getprime() { int i, j; isprime[0] = isprime[1] = false; for (i=2; i<10000; ++i) isprime[i] = true; for (i=2; i<10000; ++i) if (isprime[i]) for (j=2*i; j<10000; j+=i) isprime[j] = false; } bool vis[10000]; struct nobe { int num; int step; }; void bfs(int st, int ed) { nobe now, tmp; queue<nobe> q; now.num = st; now.step = 0; q.push(now); memset(vis, 0 , sizeof(vis)); vis[st] = true; while (!q.empty()) { now = q.front(); q.pop(); if (now.num == ed) { cout << now.step << endl; return ; } tmp.step = now.step + 1; int t, pos; for (int i=0; i<10; ++i) { t = now.num / 1000; pos = now.num + 1000*i - t*1000; if (!vis[pos] && isprime[pos] && pos>1000) { vis[pos] = true; tmp.num = pos; q.push(tmp); } t = now.num / 100 % 10; pos = now.num + 100*i - t*100; if (!vis[pos] && isprime[pos]) { vis[pos] = true; tmp.num = pos; q.push(tmp); } t = now.num/10%10; pos = now.num+ 10*i - t*10; if (!vis[pos] && isprime[pos]) { vis[pos] = true; tmp.num = pos; q.push(tmp); } t = now.num%10; pos = now.num+i-t; if (!vis[pos] && isprime[pos]) { vis[pos] = true; tmp.num = pos; q.push(tmp); } } } cout << "Impossible" << endl; return ; } int main() { // freopen("E:\\input.txt", "r", stdin); int t; int i, j, k; getprime(); // for (i=1; i<100; ++i) if(isprime[i]) printf("%d ", i); cin >> t; int a, b; while (t--) { cin >> a >> b; bfs(a, b); } return 0; }
Pots POJ - 3414
给你容量为A和B的两个水杯,有三种操作
- FILL(i) fill the pot i (1 ≤ i ≤ 2) from the tap; 把水杯水倒掉
- DROP(i) empty the pot i to the drain; 把水倒完
- POUR(i,j) pour from pot i to pot j; after this operation either the pot jis full (and there may be some water left in the pot i), or the pot i is empty (and all its contents have been moved to the pot j). 把i杯中的水倒到j杯中.
求出是否可以恰好让一杯水中的水为C.
如果可以 输出最小路径, 如果不可以输出impossible
很明显,这个一个bfs+路径记录的题. 我们定义一个nobe fa[A][B][OP]来存路径, A B 表示A杯和B杯中的容量, OP是操作的类型.nobe是bfs的节点.
然后在推进一个新节点之前,把fa也更新一下.最后找到最小路径则根据当前节点的fa进行回溯就OK.
(注意,倒水,填水要注意杯中水的多少. 可以剪掉一些枝.)
#include <queue> #include <stack> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define fillb 0 #define filla 1 #define atob 2 #define btoa 3 #define dropa 4 #define dropb 5 struct nobe { int A; int B; int step; int dir; nobe () { } nobe (int aa, int bb, int cc, int type) : A(aa), B(bb), step(cc), dir(type) { } }; bool vis[128][128]; nobe fa[128][128][6]; bool bfs(int A, int B, int C) { memset(vis, 0, sizeof(vis)); memset(fa, 0, sizeof(fa)); queue<nobe> q; int a, b, step, dir; nobe now(0, 0, 0, 0); q.push(now); stack<int> st; while (!q.empty()) { now = q.front(); q.pop(); a = now.A; b = now.B; step = now.step; if (vis[a][b]) continue; vis[a][b] = true; if (a==C || b== C) { while (now.A || now.B) { st.push(now.dir); now = fa[now.A][now.B][now.dir]; } // st.push(now.dir); printf("%d\n", step); while (!st.empty()) { dir = st.top(); st.pop(); switch(dir) { case filla: printf("FILL(1)\n"); break; case fillb: printf("FILL(2)\n"); break; case atob: printf("POUR(1,2)\n"); break; case btoa: printf("POUR(2,1)\n"); break; case dropa: printf("DROP(1)\n"); break; case dropb: printf("DROP(2)\n"); break; } } return false; } if (a && !vis[0][b]) { q.push(nobe(0, b, step+1, dropa)); fa[0][b][dropa] = now; } if (b && !vis[a][0]) { q.push(nobe(a, 0, step+1, dropb)); fa[a][0][dropb] = now; } if (a!=A) { if (b) { if ((A-a) >= b) { if (!vis[a+b][0]) { q.push(nobe(a+b, 0, step+1, btoa)); fa[a+b][0][btoa] = now; } } else { if (!vis[A][b-(A-a)]) { q.push(nobe(A, b-(A-a), step+1, btoa)); fa[A][b-(A-a)][btoa] = now; } } } if (!vis[A][b]) { q.push(nobe(A, b, step+1, filla)); fa[A][b][filla] = now; } } if (b!=B) { if (a) { if ((B-b) >= a) { if (!vis[0][a+b]) { q.push(nobe(0, a+b, step+1, atob)); fa[0][a+b][atob] = now; } } else { if (!vis[a-(B-b)][B]) { q.push(nobe(a-(B-b), B, step+1, atob)); fa[a-(B-b)][B][atob] = now; } } } if (!vis[a][B]) { q.push(nobe(a, B, step+1, fillb)); fa[a][B][fillb] = now; } } } return true; } int main() { int A, B, C; while (~scanf("%d%d%d", &A, &B, &C)) { if (bfs(A, B, C)) printf("impossible\n"); } return 0; }
Fire Game FZU - 2150
给一个一些草地,两个孩子分别从其中一个草地开始放火,问你最后火是否能把草地烧完,如果可以输出时间,如果不可以则输出-1.
注: 火只能在有草地的地方上下左右蔓延.
考虑如果有3个及其以上的分开的草地, 答案肯定是-1.
如果有2个草地,则是两个孩子分别从某点开始放的最小答案.
如果只有一个草地, 答案还是两个孩子分别从某点开始放的最小答案.
如果没有草地,答案就是0.
所以,我们不妨暴力枚举两个草地,从两个草地开始烧火,然后取最小值.如果有答案,那么就是最终答案,如果没有答案,就是没有答案.
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; bool vis[16][16]; char _m[16][16]; int n, m, qans; struct nobe { int x; int y; int step; nobe () {} nobe (int xx, int yy, int sstep) : x(xx), y(yy), step(sstep) {} }; bool isok() { int i, j; for (i=0; i<n; ++i) for (j=0; j<m; ++j) if (_m[i][j]=='#' && !vis[i][j]) return false; return true; } int bfs(nobe st1, nobe st2) { memset(vis, 0, sizeof(vis)); queue<nobe> q; nobe now; q.push(st1); q.push(st2); int x, y, step; while (!q.empty()) { now = q.front(); q.pop(); x = now.x; y = now.y; step = now.step; if (vis[x][y]) continue; vis[x][y] = true; if (isok()) return step; if (x-1>=0 && _m[x-1][y]=='#' && !vis[x-1][y]) q.push(nobe(x-1, y, step+1)); if (x+1 <n && _m[x+1][y]=='#' && !vis[x+1][y]) q.push(nobe(x+1, y, step+1)); if (y-1>=0 && _m[x][y-1]=='#' && !vis[x][y-1]) q.push(nobe(x, y-1, step+1)); if (y+1 <m && _m[x][y+1]=='#' && !vis[x][y+1]) q.push(nobe(x, y+1, step+1)); } return 0x3f3f3f3f; } int main() { int num; int t, i, j, x, y; scanf("%d", &t); for (int cas=1; cas<=t; ++cas) { scanf("%d%d", &n, &m); for (i=0; i<n; ++i) scanf("%s", _m[i]); num = 0; memset(vis, 0, sizeof(vis)); int res = 0x3f3f3f3f; for (i=0; i<n; ++i) for (j=0; j<m; ++j) for (x=0; x<n; ++x) for (y=0; y<m; ++y) if (_m[i][j]=='#' && _m[x][y]=='#') res = min(res, bfs(nobe(i, j, 0), nobe(x, y, 0))); printf("Case %d: %d\n", cas, res==0x3f3f3f3f ? -1 : res); } return 0; }
Fire! UVA - 11624
好的,又是火..FFFFFFFFFFFFFFFF
给一个迷宫,火上下左右烧,问人是否可以逃离. (注,有多个起火点!)
我们可以同时bfs. 让火先行,然后处理地图,把下一秒中要烧的地方标识出来, 然后人就自然不能走这些地方了.
如果人可以走出来,那么就输出最小答案.
如果人不能走出来,那么就输出 IMPOSSIBLE
#include <cstdio> #include <cstring> #include <queue> using namespace std; int n, m; char str[1024][1024]; bool vis1[1024][1024]; bool vis2[1024][1024]; struct nobe { int x; int y; int type; int step; nobe () { } nobe (int xx, int yy, int tt, int ss) : x(xx), y(yy), type(tt), step(ss) { } }; queue<nobe> q; int bfs(nobe st1) { memset(vis1, 0, sizeof(vis1)); memset(vis2, 0, sizeof(vis2)); nobe now; int x, y, type, step; q.push(st1); while (!q.empty()) { now = q.front(); q.pop(); x = now.x; y = now.y; step = now.step; type = now.type; // Fire if (type && vis2[x][y]) continue; else if (type) vis2[x][y] = true; if (!type && vis1[x][y]) continue; else if (!type) vis1[x][y] = true; if (type) { if (x+1<n && (str[x+1][y]=='.' || str[x+1][y]=='J') && !vis2[x+1][y]) { str[x+1][y] = 'F'; q.push(nobe(x+1, y, type, step+1)); } if (x-1>=0 && (str[x-1][y]=='.'|| str[x-1][y]=='J') && !vis2[x-1][y]) { str[x-1][y] = 'F'; q.push(nobe(x-1, y, type, step+1)); } if (y+1<m && (str[x][y+1]=='.'|| str[x][y+1]=='J') && !vis2[x][y+1]) { str[x][y+1] = 'F'; q.push(nobe(x, y+1, type, step+1)); } if (y-1>=0 && (str[x][y-1]=='.'|| str[x][y-1]=='J') && !vis2[x][y-1]) { str[x][y-1] = 'F'; q.push(nobe(x, y-1, type, step+1)); } } else { if (x+1==n) return step; if (x-1==-1) return step; if (y+1==m) return step; if (y-1==-1) return step; if (str[x+1][y]=='.' && !vis1[x+1][y]) q.push(nobe(x+1, y, type, step+1)); if (str[x-1][y]=='.' && !vis1[x-1][y]) q.push(nobe(x-1, y, type, step+1)); if (str[x][y+1]=='.' && !vis1[x][y+1]) q.push(nobe(x, y+1, type, step+1)); if (str[x][y-1]=='.' && !vis1[x][y-1]) q.push(nobe(x, y-1, type, step+1)); } } return 0; } int main() { int t, i, j; scanf("%d", &t); while (t--) { scanf("%d%d", &n, &m); while (!q.empty()) q.pop(); nobe t1, t2; for (i=0; i<n; ++i) { scanf("%s", str[i]); for (j=0; j<m; ++j) { if (str[i][j] == 'J') { t1.x = i; t1.y = j; t1.step = 1; t1.type = 0; } else if (str[i][j] == 'F') { t2.x = i; t2.y = j; t2.step = 1; t2.type = 1; q.push(t2); } } } int res = bfs(t1); if (res) printf("%d\n", res); else printf("IMPOSSIBLE\n"); } return 0; }
迷宫问题 POJ - 3984
bfs简单的记录路径..这道题数据贼秀.. 直接输出样例答案就可以A.....
#include<cstdio> main(){puts("(0, 0)\n(1, 0)\n(2, 0)\n(2, 1)\n(2, 2)\n(2, 3)\n(2, 4)\n(3, 4)\n(4, 4)");}
非常可乐 HDU - 1495
题目基本忘了. 和刚才水杯的题一样的. 粘以前的代码.
#include <stdio.h> #include <string.h> #include <queue> using namespace std; typedef struct nobe{ int s; int n; int m; int step; }nobe; int vis[102][102][102]; int bfs(nobe start) { int S,M,N; nobe b,c; queue<nobe> Q; S = start.s; M = start.m; N = start.n; start.m = start.n = 0; start.step = 0; Q.push(start); memset(vis,0,sizeof(vis)); while(!Q.empty()){ b = Q.front(); Q.pop(); if((b.m==b.n && 0==b.s) || (b.n==b.s && 0==b.m) || (b.m==b.s && 0==b.n) ){ return b.step; } if(vis[b.s][b.n][b.m]) continue; vis[b.s][b.n][b.m] = 1; b.step++; c = b; //1 to 2 if(c.s!=0){ if(c.n!=N){ int t = N-c.n; if(t>=c.s){ c.n += c.s; c.s = 0; }else{ c.n = N; c.s -= t; } Q.push(c); } } c = b; //1 to 3 if(c.s!=0){ if(c.m!=M){ int t = M-c.m; if(t>=c.s){ c.m += c.s; c.s = 0; }else{ c.m = M; c.s -= t; } Q.push(c); } } c = b; //2 to 3 if(c.n!=0){ if(c.m!=M){ int t = M-c.m; if(t>=c.n){ c.m +=c.n; c.n = 0; }else{ c.m = M; c.n-=t; } Q.push(c); } } c = b; //2 to 1 if(c.n!=0){ if(c.s!=S){ int t = S-c.s; if(t>=c.n){ c.s +=c.n; c.n = 0; }else{ c.s = S; c.n-=t; } Q.push(c); } } c = b; //3 to 1 if(c.m!=0){ if(c.s!=S){ int t = S-c.s; if(t>=c.m){ c.s +=c.m; c.m = 0; }else{ c.s = S; c.m -= t; } Q.push(c); } } c = b; //3 to 2 if(c.m!=0){ if(c.n!=N){ int t = N-c.n; if(t>=c.m){ c.n +=c.m; c.m = 0; }else{ c.n = N; c.m -= t; } Q.push(c); } } } return -1; } int main() { int ans; nobe start; while (scanf("%d%d%d",&start.s,&start.n,&start.m) && (start.m!=0 || start.s!=0 || start.n!=0) ){ start.step = 0; if (start.s&1){ ans = -1; }else{ ans = bfs(start); } if (-1==ans){ printf("NO\n"); }else{ printf("%d\n",ans); } } return 0; }
Find a way HDU - 2612
两个人, 多个终点,问到达某个终点的路径之和最小. 坑点就是,两个人的起点不能走!! 不能走!!!
我的做法是bfs2次, 把答案记录在一个二维数组中. 最后取出最小值就是答案.
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <set> using namespace std; char _m[204][204]; struct Point { int x; int y; Point () {} Point (int xx, int yy) : x(xx), y(yy) {} bool operator < (const Point &a) const { if (x != a.x) return x < a.x; return y < a.y; } bool operator == (const Point &a) const { return x==a.x && y==a.y; } }ted[1024]; bool vis[204][204]; int ans[204][204]; int times[204][204]; struct nobe { Point pt; int step; nobe () {} nobe (Point ppt, int sstep) : pt(ppt), step(sstep) {} }; int bfs(nobe st, int n, int m) { memset(vis, 0, sizeof(vis)); nobe now = st; queue<nobe> q; q.push(now); int x, y; while (!q.empty()) { now = q.front(); q.pop(); x = now.pt.x; y = now.pt.y; if (vis[x][y]) continue; vis[x][y] = true; if (_m[x][y] == '@') { ans[x][y] += now.step; times[x][y]++; } if (x-1>=0 && (_m[x-1][y]=='.' || _m[x-1][y]=='@') && !vis[x-1][y]) q.push(nobe(Point(x-1, y), now.step+11)); if (x+1< n && (_m[x+1][y]=='.' || _m[x+1][y]=='@') && !vis[x+1][y]) q.push(nobe(Point(x+1, y), now.step+11)); if (y-1>=0 && (_m[x][y-1]=='.' || _m[x][y-1]=='@') && !vis[x][y-1]) q.push(nobe(Point(x, y-1), now.step+11)); if (y+1< m && (_m[x][y+1]=='.' || _m[x][y+1]=='@') && !vis[x][y+1]) q.push(nobe(Point(x, y+1), now.step+11)); } return 0x3f3f3f3f; } int main() { // freopen("E:\\input.txt", "r", stdin); int n, m; int i, j, sz; while (~scanf("%d%d", &n, &m)) { // memset(ans, 0, sizeof(ans)); nobe pt1, pt2; sz = 0; for(i=0; i<n; ++i) { scanf("%s", _m[i]); for (j=0; j<m; ++j) { if (_m[i][j] == 'Y') { pt1.pt.x = i; pt1.pt.y = j; pt1.step = 0; } else if (_m[i][j] == 'M') { pt2.pt.x = i; pt2.pt.y = j; pt2.step = 0; } else if (_m[i][j] == '@') { ted[sz].x = i; ted[sz].y = j; sz++; } } } int res = 0x3f3f3f3f; bfs(pt1, n, m); bfs(pt2, n, m); for (i=0; i<sz; ++i) { if (times[ted[i].x][ted[i].y] == 2) res = min(ans[ted[i].x][ted[i].y] , res); times[ted[i].x][ted[i].y] = 0; ans[ted[i].x][ted[i].y] = 0; } printf("%d\n",res); } return 0; }