搜索专题(Newer)
题解:
A bfs依次遍历周围的八个方向(马走日)
B bfs注意记录当前方向和转弯数
C bfs入门题目,注意要清空队列
D dfs入门,周围加边四个方向深搜即可。
E dfs.八连块问题 只要周围的八个方向的图是一样的,则都算是同一个八连块,记录共有多少个八连块即可。
D dfs 深度遍历每一条路即可,只是要边遍历边记录路径,最后输出路径就好了
E dfs+奇偶剪枝优化
ID | Title | ||
---|---|---|---|
13 / 19 | Problem A | Knight Moves | |
6 / 38 | Problem B | 逃离迷宫 | |
8 / 40 | Problem C | Catch That Cow | |
8 / 8 | Problem D | Red and Black | |
6 / 9 | Problem E | Oil Deposits | |
4 / 6 | Problem F | 哈密顿绕行世界问题 | |
4 / 19 | Problem G | Tempter of the Bone |
A hdu 1372
e2 e4 a1 b2 b2 c3 a1 h8 a1 h7 h8 a1 b1 c3 f6 f6
To get from e2 to e4 takes 2 knight moves. To get from a1 to b2 takes 4 knight moves. To get from b2 to c3 takes 2 knight moves. To get from a1 to h8 takes 6 knight moves. To get from a1 to h7 takes 5 knight moves. To get from h8 to a1 takes 6 knight moves. To get from b1 to c3 takes 1 knight moves. To get from f6 to f6 takes 0 knight moves.
/* 算法:bfs 思路:八个方向依次遍历即可 注意:队列元素Node 不仅包含了点的位置还包含了走到当前所用的步数 注意骑士周游问题:马走日八个方向 A Accepted 248 KB 15 ms C++ */ #include<cstdio> #include<queue> #include<cstring> #include<iostream> using namespace std; bool vis[30][30]; //标记是否走过 int dir[8][2] = { 1,2, 2,1, 2,-1, 1,-2, -1,-2, -2,-1, -2,1, -1,2 }; //马走日 八个方向 int sx, sy, ex, ey; //记录起点和终点 char s_x, e_x; struct Node { int x, y; int step; }; queue<Node> q; bool inMap(int x, int y) //判断是否在棋盘内 { if(x < 1 || x > 8 || y < 1 || y > 8) return false; return true; } void bfs(int x, int y) //广度优先遍历 { while(!q.empty()) q.pop(); //清空队列 Node start; start.x = x; start.y = y; start.step = 0; //起点 vis[x][y] = true; //标记起点已走 q.push(start); //起点入队 while(!q.empty()) //当队列非空 { Node now = q.front(); //取队首 q.pop(); //弹出队首 if(now.x == ex && now.y == ey) //到达终点 { printf("To get from %c%d to %c%d takes %d knight moves.\n", s_x, sy, e_x, ey, now.step); return; } Node next; for(int i = 0; i < 8; i++) //依次遍历每个点的八个方向 { next.x = now.x+dir[i][0]; next.y = now.y+dir[i][1]; if(!inMap(next.x, next.y)) continue; //不在图中,则跳过此点 if(!vis[next.x][next.y]) //没有被遍历过 { vis[next.x][next.y] = true; //记录已被遍历 next.step = now.step+1; //确定条到这一步,步数+1 q.push(next); //入队 if(next.x == ex && next.y == ey) //如果到达终点 { printf("To get from %c%d to %c%d takes %d knight moves.\n", s_x, sy, e_x, ey, next.step); return; } } } } } int main() {//freopen("in.txt", "r", stdin); while(scanf("%c%d%*c%c%d%*c", &s_x, &sy, &e_x, &ey) != EOF) {//注意输入时的*c 运行bfs前可以自己测试一下 ,最好还是用cin输入了 memset(vis, false, sizeof(vis)); //初始化遍历数组 sx = s_x-'a'+1; //字符数字化 ex = e_x-'a'+1; bfs(sx, sy); } return 0; }
B_hdu 1728
2 5 5 ...** *.**. ..... ..... *.... 1 1 1 1 3 5 5 ...** *.**. ..... ..... *.... 2 1 1 1 3
no yes
/* 算法:暴力 bfs 思路:还是像以前一样定义一个结构体入队。 但是结构体中除了原来定义过的 x,y坐标 还新加了turn(走到当前点,转的弯),dir(当前方向)。 注意:放向的转换,纠结了好久,最后看了篇题解,每个点都记录了方向就解决了。 输入:确定起点和终点时是先输入列再输入行。 输出:小写输出,开始没注意一直WA到死啊。 B Accepted 412 KB 62 ms C++ 830 B */ #include<cstdio> #include<queue> #include<iostream> using namespace std; const int maxn = 105; const int Max = 1<<30; //作为初始化值 char map[maxn][maxn]; int turn[maxn][maxn]; //记录走到当前坐标转的弯 int dir[4][2] = { 0,1, 1,0, 0,-1, -1,0}; //上下左右四个方向都可以走 int k, sx, sy, ex, ey; int m, n; struct Node { int x, y; //点的位置 int turn ,dir; //转的弯和当前方向 }; queue<Node> q; //结构体队列 bool inMap(int x, int y) //判断是否在图中 { if(x < 1 || x > m || y < 1 || y > n) return false; return true; } void bfs(int x, int y) { while(!q.empty()) q.pop(); //清空队列 Node start; start.x = x; start.y = y; start.turn = 0; start.dir = -1; //起点 turn[x][y] = 0; //起点可以任意转弯 q.push(start); //入队 while(!q.empty()) //当队列非空 { Node now = q.front(); // 取队首 q.pop(); //弹出队首 Node next; for(int i = 0; i < 4; i++) //依次遍历周围的四个方向 { next = now; next.x += dir[i][0]; next.y += dir[i][1]; //如果不在图中,或者不可以走,则跳过此点 if(!inMap(next.x, next.y) || map[next.x][next.y] == '*') continue; //如果当前点now不是起点,而且转入的方向与原方向不同,则当前点转弯数+1 if(next.dir != -1 && next.dir != i) next.turn++; //如果走到当前点转的弯超过了限定的转弯数,则跳过此点 if(next.turn > k) continue; //如果当前点符合要求,输出yes结束程序 if(next.turn <= k && next.x == ex && next.y == ey) { printf("yes\n"); return; } //否则当前点入队 if(turn[next.x][next.y] >= next.turn) { turn[next.x][next.y] = next.turn; next.dir = i; q.push(next); } } } printf("no\n"); //遍历完所有均不能满足条件 return; } int main() {//freopen("in.txt", "r", stdin); int T; scanf("%d", &T); //T组测试数据 while(T--) { scanf("%d%d", &m, &n); //m行n列 for(int i = 1; i <= m; i++) { for(int j = 1; j <= n; j++) { cin>>map[i][j]; turn[i][j] = Max; //初始化转弯数为最大值 } } cin>>k>>sy>>sx>>ey>>ex; //注意输入的顺序 if(sx == ex && sy == ey) printf("yes\n"); //如果相等,则直接输出注意小写输出 else bfs(sx, sy); } return 0; }
C_hdu 2717
POJ_3278
5 17
4HintThe fastest way for Farmer John to reach the fugitive cow is to move along the following path: 5-10-9-18-17, which takes 4 minutes.
下面的代码已经很清楚了,如果还是不了解,请看我的分析博客:点击打开链接
//Accepted 984K 79MS C++ 1128B 2012-11-10 00:44:26 #include<iostream> #include<queue> #include<cstring> #include<cstdio> using namespace std; const int maxn=100001; bool vis[maxn];//标记数组 int step[maxn];//记录到了每一位置所走的步数 queue <int> q;//定义队列 int bfs(int n,int k) { int head,next; q.push(n); //开始FJ在n位置,n入队 step[n]=0; vis[n]=true; //标记已访问 while(!q.empty()) //当队列非空 { head=q.front(); //取队首 q.pop(); //弹出对首 for(int i=0;i<3;i++) //FJ的三种走法 { if(i==0) next=head-1; else if(i==1) next=head+1; else next=head*2; if(next<0 || next>=maxn) continue; //排除出界情况 if(!vis[next]) //如果next位置未被访问 { q.push(next); //入队 step[next]=step[head]+1; //步数+1 vis[next]=true; //标记已访问 } if(next==k) return step[next]; //当遍历到结果,返回步数 } } } int main() { int n,k; while(cin>>n>>k) { memset(step,0,sizeof(step)); memset(vis,false,sizeof(vis)); while(!q.empty()) q.pop(); //注意调用前要先清空 if(n>=k) printf("%d\n",n-k); else printf("%d\n",bfs(n,k)); } return 0; }
D_hdu 1312
POJ 1979
6 9 ....#. .....# ...... ...... ...... ...... ...... #@...# .#..#. 11 9 .#......... .#.#######. .#.#.....#. .#.#.###.#. .#.#..@#.#. .#.#####.#. .#.......#. .#########. ........... 11 6 ..#..#..#.. ..#..#..#.. ..#..#..### ..#..#..#@. ..#..#..#.. ..#..#..#.. 7 7 ..#.#.. ..#.#.. ###.### ...@... ###.### ..#.#.. ..#.#.. 0 0
45 59 6 13
/* 题意:'#'不可走,'.'可走,'@'为起点。 求从'@'开始走,一共可以走完多少个'.','@'也算一个。 思路:dfs深度遍历周围的四个方向 优化:遍历前,图的四周加边。 注意:先输入高度,再输入宽。也就是先输入行数再输入列数。 D Accepted 268 KB 15 ms C++ 876 B */ #include<cstdio> #include<cstring> #include<iostream> using namespace std; char map[25][25]; int w, h; int sx, sy; //起点 int ans; void dfs(int x, int y) //深度遍历 { if(map[x][y] == '#') return; //不可走,马上跳出 ans++; //可以走 结果+1 map[x][y] = '#'; // 标记已走 dfs(x-1, y); dfs(x+1, y); //遍历周围的四个方向 dfs(x, y-1); dfs(x, y+1); } int main() { while(scanf("%d%d", &w, &h) != EOF) //先输入列数 再输入行数 { if(w == 0) break; // 输入0即结束 for(int i = 1; i <= h; i++) { for(int j = 1; j <= w; j++) { cin>>map[i][j]; if(map[i][j] == '@') //起点 { sx = i; sy = j; } } } for(int i = 0; i <= h+1; i++) map[i][0] = map[i][w+1] = '#'; //第0列和第w+1列加边 不可走 for(int i = 0; i <= w+1; i++) map[0][i] = map[h+1][i] = '#'; //第0行和第h+1行加边 不可走 ans = 0; //初始化结果 dfs(sx, sy); printf("%d\n", ans); } return 0; }
hdu 1241
POJ 1562
1 1 * 3 5 *@*@* **@** *@*@* 1 8 @@****@* 5 5 ****@ *@@*@ *@**@ @@@*@ @@**@ 0 0
0 1 2 2
F
hdu 2181
2 5 20 1 3 12 2 4 10 3 5 8 1 4 6 5 7 19 6 8 17 4 7 9 8 10 16 3 9 11 10 12 15 2 11 13 12 14 20 13 15 18 11 14 16 9 15 17 7 16 18 14 17 19 6 18 20 1 13 19 5 0
1: 5 1 2 3 4 8 7 17 18 14 15 16 9 10 11 12 13 20 19 6 5 2: 5 1 2 3 4 8 9 10 11 12 13 20 19 18 14 15 16 17 7 6 5 3: 5 1 2 3 10 9 16 17 18 14 15 11 12 13 20 19 6 7 8 4 5 4: 5 1 2 3 10 11 12 13 20 19 6 7 17 18 14 15 16 9 8 4 5 5: 5 1 2 12 11 10 3 4 8 9 16 15 14 13 20 19 18 17 7 6 5 6: 5 1 2 12 11 15 14 13 20 19 18 17 16 9 10 3 4 8 7 6 5 7: 5 1 2 12 11 15 16 9 10 3 4 8 7 17 18 14 13 20 19 6 5 8: 5 1 2 12 11 15 16 17 18 14 13 20 19 6 7 8 9 10 3 4 5 9: 5 1 2 12 13 20 19 6 7 8 9 16 17 18 14 15 11 10 3 4 5 10: 5 1 2 12 13 20 19 18 14 15 11 10 3 4 8 9 16 17 7 6 5 11: 5 1 20 13 12 2 3 4 8 7 17 16 9 10 11 15 14 18 19 6 5 12: 5 1 20 13 12 2 3 10 11 15 14 18 19 6 7 17 16 9 8 4 5 13: 5 1 20 13 14 15 11 12 2 3 10 9 16 17 18 19 6 7 8 4 5 14: 5 1 20 13 14 15 16 9 10 11 12 2 3 4 8 7 17 18 19 6 5 15: 5 1 20 13 14 15 16 17 18 19 6 7 8 9 10 11 12 2 3 4 5 16: 5 1 20 13 14 18 19 6 7 17 16 15 11 12 2 3 10 9 8 4 5 17: 5 1 20 19 6 7 8 9 10 11 15 16 17 18 14 13 12 2 3 4 5 18: 5 1 20 19 6 7 17 18 14 13 12 2 3 10 11 15 16 9 8 4 5 19: 5 1 20 19 18 14 13 12 2 3 4 8 9 10 11 15 16 17 7 6 5 20: 5 1 20 19 18 17 16 9 10 11 15 14 13 12 2 3 4 8 7 6 5 21: 5 4 3 2 1 20 13 12 11 10 9 8 7 17 16 15 14 18 19 6 5 22: 5 4 3 2 1 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 23: 5 4 3 2 12 11 10 9 8 7 6 19 18 17 16 15 14 13 20 1 5 24: 5 4 3 2 12 13 14 18 17 16 15 11 10 9 8 7 6 19 20 1 5 25: 5 4 3 10 9 8 7 6 19 20 13 14 18 17 16 15 11 12 2 1 5 26: 5 4 3 10 9 8 7 17 16 15 11 12 2 1 20 13 14 18 19 6 5 27: 5 4 3 10 11 12 2 1 20 13 14 15 16 9 8 7 17 18 19 6 5 28: 5 4 3 10 11 15 14 13 12 2 1 20 19 18 17 16 9 8 7 6 5 29: 5 4 3 10 11 15 14 18 17 16 9 8 7 6 19 20 13 12 2 1 5 30: 5 4 3 10 11 15 16 9 8 7 17 18 14 13 12 2 1 20 19 6 5 31: 5 4 8 7 6 19 18 17 16 9 10 3 2 12 11 15 14 13 20 1 5 32: 5 4 8 7 6 19 20 13 12 11 15 14 18 17 16 9 10 3 2 1 5 33: 5 4 8 7 17 16 9 10 3 2 1 20 13 12 11 15 14 18 19 6 5 34: 5 4 8 7 17 18 14 13 12 11 15 16 9 10 3 2 1 20 19 6 5 35: 5 4 8 9 10 3 2 1 20 19 18 14 13 12 11 15 16 17 7 6 5 36: 5 4 8 9 10 3 2 12 11 15 16 17 7 6 19 18 14 13 20 1 5 37: 5 4 8 9 16 15 11 10 3 2 12 13 14 18 17 7 6 19 20 1 5 38: 5 4 8 9 16 15 14 13 12 11 10 3 2 1 20 19 18 17 7 6 5 39: 5 4 8 9 16 15 14 18 17 7 6 19 20 13 12 11 10 3 2 1 5 40: 5 4 8 9 16 17 7 6 19 18 14 15 11 10 3 2 12 13 20 1 5 41: 5 6 7 8 4 3 2 12 13 14 15 11 10 9 16 17 18 19 20 1 5 42: 5 6 7 8 4 3 10 9 16 17 18 19 20 13 14 15 11 12 2 1 5 43: 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 1 2 3 4 5 44: 5 6 7 8 9 16 17 18 19 20 1 2 12 13 14 15 11 10 3 4 5 45: 5 6 7 17 16 9 8 4 3 10 11 15 14 18 19 20 13 12 2 1 5 46: 5 6 7 17 16 15 11 10 9 8 4 3 2 12 13 14 18 19 20 1 5 47: 5 6 7 17 16 15 11 12 13 14 18 19 20 1 2 3 10 9 8 4 5 48: 5 6 7 17 16 15 14 18 19 20 13 12 11 10 9 8 4 3 2 1 5 49: 5 6 7 17 18 19 20 1 2 3 10 11 12 13 14 15 16 9 8 4 5 50: 5 6 7 17 18 19 20 13 14 15 16 9 8 4 3 10 11 12 2 1 5 51: 5 6 19 18 14 13 20 1 2 12 11 15 16 17 7 8 9 10 3 4 5 52: 5 6 19 18 14 15 11 10 9 16 17 7 8 4 3 2 12 13 20 1 5 53: 5 6 19 18 14 15 11 12 13 20 1 2 3 10 9 16 17 7 8 4 5 54: 5 6 19 18 14 15 16 17 7 8 9 10 11 12 13 20 1 2 3 4 5 55: 5 6 19 18 17 7 8 4 3 2 12 11 10 9 16 15 14 13 20 1 5 56: 5 6 19 18 17 7 8 9 16 15 14 13 20 1 2 12 11 10 3 4 5 57: 5 6 19 20 1 2 3 10 9 16 15 11 12 13 14 18 17 7 8 4 5 58: 5 6 19 20 1 2 12 13 14 18 17 7 8 9 16 15 11 10 3 4 5 59: 5 6 19 20 13 12 11 10 9 16 15 14 18 17 7 8 4 3 2 1 5 60: 5 6 19 20 13 14 18 17 7 8 4 3 10 9 16 15 11 12 2 1 5
/* *F *Accepted *204 KB *0 ms *G++ *867 B *2013-03-26 */ #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int path[22]; int point[21][3]; bool vis[21]; int m; int Case; void dfs(int a, int n) { vis[a] = true; path[n] = a; if(n == 21 && path[n] == m) //回到起点 { printf("%d: ",++Case); for(int i = 1; i <= 21; i++) printf(" %d", path[i]); printf("\n"); return; } else if(n >= 21) return; for(int i = 0; i < 3; i++) { int x = point[a][i]; if((x != m && !vis[x]) || (x == m && n == 20)) //如果没有走过,或者下一个点回到起点 { //注意:前一个条件如果没有写 x != m 则会影响后面的结果 也就是 m 会在路径中重复出现 dfs(x, n+1); vis[x] = false; } } } int main() { for(int i = 1; i <= 20; i++) { scanf("%d%d%d", &point[i][0], &point[i][1], &point[i][2]); sort(point[i], point[i]+3); } while(scanf("%d", &m) != EOF) { Case = 0; if(m == 0) break; memset(vis, false, sizeof(vis)); dfs(m, 1); } return 0; }
G_hdu 1010
4 4 5 S.X. ..X. ..XD .... 3 4 5 S.X. ..X. ...D 0 0 0
NO YES