一、DFS
1.迷宫问题
Description
Input
迷宫使用0和1字符表示,0表示有路1表示为墙.迷宫为正方形.左上角为(1,1),右下角为(N,N).左上角为入口,出口在(N,N).
输入第一行有3个正整数N,x,y.
N表示迷宫规模,x,y表示Jack和同学所在的迷宫位置. 要求找出从(x,y)到(N,N)的路径( N ≤ 80 ). 且出口和入口的值一定为0
下边为迷宫的字符模型用01表示.
Output
Sample Input
6 5 2 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 0 1 1 1 0 0 0 1 1 1 0 1 0 1 1 1 0 1 0 0 0
Sample Output
Found 0 0 1 1 1 1 1 0 0 # # 1 1 1 1 # 1 1 1 0 0 # 1 1 1 0 1 # 1 1 1 0 1 # # #
Hint
Source
solution:
#include<stdio.h> const int M=81; int maze[M][M],n; int dir[][2]={{0,1},{1,0},{0,-1},{-1,0}}; bool dfs(int x,int y) { maze[x][y]=-1; for(int i=0; i<4; ++i) { int nextx=x+dir[i][0]; int nexty=y+dir[i][1]; if(nextx==n && nexty==n) { maze[nextx][nexty]=-1; return 1; } else if(nextx==0||nextx==n+1||nexty==0||nexty==n+1||maze[nextx][nexty]!=0) continue; else if(dfs(nextx,nexty)) { maze[nextx][nexty]=-1; return 1; } } maze[x][y]=0; return 0; } int main() { int x,y,i,j; while(scanf("%d %d %d",&n,&y,&x)!=EOF) { for(i=1; i<=n; i++) for(j=1; j<=n; j++) scanf("%d",&maze[i][j]); if(dfs(x,y)) { printf("Found\n"); for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { if(maze[i][j]==-1) printf("# "); else printf("%d ",maze[i][j]); } printf("\n"); } } else printf("Not Found\n"); } return 0; }
给大一同学讲题的时候这题当场没写出来。。。
重写了一遍,感觉当时没有体会到回溯上一行return的意义,把dfs彻底当成brutal了。
代码:
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> using namespace std; char g[100][100]; int dir[][4] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; int n; bool dfs(int x, int y) { if (x == n && y == n) return true; for (int i = 0; i < 4; i++) { int nx = x + dir[i][0]; int ny = y + dir[i][1]; if (1 <= nx && nx <= n && 1 <= ny && ny <= n && g[nx][ny] == '0') { g[nx][ny] = '#'; if (dfs(nx, ny)) return true; g[nx][ny] = '0'; } } return false; } int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); #endif // LOCAL int x, y; while (scanf("%d%d%d", &n, &y, &x) == 3) { getchar(); for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { scanf("%c", &g[i][j]); getchar(); } } g[x][y] = '#'; if (dfs(x, y)) { printf("Found\n"); for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { printf("%c ", g[i][j]); } printf("\n"); } } else printf("Not Found\n"); } return 0; }
2.图的连通性问题
(1).找油田
Description
Input
Output
Sample Input
1 1 * 3 5 *@*@* **@** *@*@* 1 8 @@****@* 5 5 ****@ *@@*@ *@**@ @@@*@ @@**@ 0 0
Sample Output
0 1 2 2
Source
solution:
这题让我真正见识到dfs的魅力所在,解决连通性的利刃。
#include<stdio.h> const int N=101; int dir[][2]= {{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}}; char oil[N][N]; int m,n; void dfs(int x,int y) { if(oil[x][y]!='@'||x==0||y==0||x==m+1||y==n+1) return; else { oil[x][y]='0'; for(int i=0; i<8; i++) { dfs(x+dir[i][0],y+dir[i][1]); } } } int main() { int i,j; while(scanf("%d%d",&m,&n)!=EOF) { int s=0; if(m==0&&n==0) break; getchar(); for(i=1; i<=m; i++) { for(j=1; j<=n; j++) { scanf("%c",&oil[i][j]); } getchar(); } for(i=1; i<=m; i++) { for(j=1; j<=n; j++) { if(oil[i][j]=='@') { dfs(i,j); s++; } } } printf("%d\n",s); } return 0; }
(2).找水洼
Description
Due to recent rains, water has pooled in various places in Farmer John's field, which is represented by a rectangle of N x M (1 <= N <= 100; 1 <= M <= 100) squares. Each square contains either water ('W') or dry land ('.'). Farmer John would like to figure out how many ponds have formed in his field. A pond is a connected set of squares with water in them, where a square is considered adjacent to all eight of its neighbors.
Given a diagram of Farmer John's field, determine how many ponds he has.Input
Output
Sample Input
10 12 W........WW. .WWW.....WWW ....WW...WW. .........WW. .........W.. ..W......W.. .W.W.....WW. W.W.W.....W. .W.W......W. ..W.......W.
Sample Output
3
Hint
Source
#include<stdio.h> const int N=101; int m,n; char lake[N][N]; int dir[][2]={{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}}; void dfs(int x,int y) { if(lake[x][y]!='W'||x==0||y==0||x==m+1||y==n+1) return; else { lake[x][y]='0'; for(int i=0; i<8; i++) { dfs(x+dir[i][0],y+dir[i][1]); } } } int main() { int i,j; while(scanf("%d%d",&m,&n)!=EOF) { int s=0; getchar(); for(i=1; i<=m; i++) { for(j=1; j<=n; j++) { scanf("%c",&lake[i][j]); } getchar(); } for(i=1; i<=m; i++) { for(j=1; j<=n; j++) { if(lake[i][j]=='W') { dfs(i,j); s++; } } } printf("%d\n",s); } return 0; }
1.类迷宫
Description
keefo 正在一个迷宫里找宝藏. keefo好不容易找到这个迷宫,这个迷宫传说中藏了不少的宝藏,当然他希望这次能够找出所所有的宝藏. 现在,他已经从杨过那里获得宝藏地图, 现在 keefo 想知道他能够获得多少宝藏.keefo 希望你能够帮他解决这个问题(呵呵~,不是白干哦, keefo会付给你酬金).
现在假设,迷宫是由正方形网格组成 . keefo在迷宫中,只能从 上 ,下,左,右四个方向移动. 但是如果他要走的前方是一堵墙的话,他将不能走过去. 并且,迷宫的四周都是由一堵厚实的墙包围着, 也就是说,keefo不可能走出迷宫之外.
Input
输入包含多组测试数据.
每组测试数据第一行包含两个整形数字, N 和 M ( 1 < N,M ≤ 1000 ), 分别表示迷宫网格的行和列.接下来N行里,每行包含了M个字符.( ´X´ 代表 keefo 当前位置 , ´*´ 代表宝藏 , ´#´代表墙, ´.´ 代表没有任何障碍 ).每个测试数据只包含一个 ´X´ 字符.
Output
输出keefo 能够找到的最多宝藏的个数.
每组数据一行.
Sample Input
4 4 *... .X.. .... ...* 4 4 *#.. #X.. .... ...*
Sample Output
2 1
Source
solution:
#include<stdio.h> #include<string.h> #include<queue> using namespace std; const int N=1001; char maze[N][N]; int n,m; int dir[][2]= {{0,1},{1,0},{0,-1},{-1,0}}; bool visit[N][N]= {0}; struct point { int x,y; }; int bfs(int x,int y) { int s=0; memset(visit,0,sizeof(visit)); queue<point> Q; point now,next; now.x=x; now.y=y; Q.push(now); visit[now.x][now.y] = 1; while(!Q.empty()) { now=Q.front(); Q.pop(); for(int i=0; i<4; i++) { next.x=now.x+dir[i][0]; next.y=now.y+dir[i][1]; if(next.x==0||next.y==0||next.x==n+1||next.y==m+1||visit[next.x][next.y]) continue; if(visit[next.x][next.y]==0) { if(maze[next.x][next.y]=='*') { s++; visit[next.x][next.y]=1; Q.push(next); } else if(maze[next.x][next.y]=='.') { visit[next.x][next.y]=1; Q.push(next); } else { continue; } } } } return s; } int main() { int i,j,x,y; while(scanf("%d %d",&n,&m)!=EOF) { getchar(); for(i=1; i<=n; i++) { for(j=1; j<=m; j++) { scanf("%c",&maze[i][j]); if(maze[i][j]=='X') { x=i; y=j; } } getchar(); } printf("%d\n",bfs(x,y)); } return 0; }
2.寻找最短路 and 3D迷宫
Description
你被关进了一个3D的地牢中,现在你需要找到最快的方法迅速的跑出监狱。 地牢是由每一个小方格组成,这些方格可能是墙壁。 假设你每移动一个单位(移动方向,可以是 东, 南, 西 ,北, 上, 下 )需要一分钟的时间。 你不能够沿对角线移动,并且不能够越过地牢,因为地牢四周被坚固的石头包围着。
你能够顺利的从这个地牢中逃脱吗? 你最少需要花多少时间呢?
Input
输入有多组测试数据。
每一个测试数据第一行有三个整形数据 L R 和 C ( L , R, C ≤ 30 )
L 表示地牢的层数 。
R 和 C 分别表示地牢每层的 行数 和 列数 。
接下来的L个地图分别表示地牢的每层地图,每个地图有R行,每行包括C个字符。 每个字符描绘着地牢的每一个小方格,´#´表示墙壁,你不能通过。´.´表示通道 。 并且你的起始地点 和终止分别是 ´S´ 和´E´.
每个地图之间间隔一行。
当L , R , C 均 为 0 时 ,表示输入结束。
Output
每一个测试数据占一行。
如果你能顺利的逃脱,那么请输出:
Escaped in x minute(s).
其中 x 表示 你逃脱所花的最短时间。
如果你不能顺利逃脱,那么请输出:
Trapped!
Sample Input
3 4 5 S.... .###. .##.. ###.# ##### ##### ##.## ##... ##### ##### #.### ####E 1 3 3 S## #E# ### 0 0 0
Sample Output
Escaped in 11 minute(s). Trapped!
Source
solution:
bfs常用来找最短路,不是证明过算导的最短路吗摔,怎么会不记得,第一次用了dfs 。。。wa了摔!!!
而所谓的3D迷宫,无非就是在平面x,y上再立一个z轴,不能斜着走的情况下只有6个方向。
代码:
#include<stdio.h> #include<string.h> #include<queue> using namespace std; char maze[31][31][31]; int L,R,C; int xe,ye,ze; int dir[][3]= {{-1,0,0},{1,0,0},{0,0,1},{0,1,0},{0,0,-1},{0,-1,0}}; bool vis[31][31][31]= {0}; struct point { int x,y,z; int num; }; bool flag; int bfs(int z,int x,int y) { memset(vis,0,sizeof(vis)); queue<point> Q; point now,next; now.z=z; now.x=x; now.y=y; now.num=0; Q.push(now); while(!Q.empty()) { now=Q.front(); Q.pop(); vis[now.z][now.x][now.y]=1; for(int i=0; i<6; i++) { next.z=now.z+dir[i][0]; next.x=now.x+dir[i][1]; next.y=now.y+dir[i][2]; if(vis[next.z][next.x][next.y]||next.z==0||next.y==0||next.x==0||next.z==L+1||next.x==R+1||next.y==C+1||maze[next.z][next.x][next.y]=='#') continue; if(next.z==ze&&next.x==xe&&next.y==ye) { flag=1; next.num=now.num+1; return next.num; } else if(maze[next.z][next.x][next.y]=='.') { next.num=now.num+1; vis[next.z][next.x][next.y]=1; Q.push(next); } } } } int main() { int i,j,k,xb,yb,zb,time; bool flag1,flag2; while(scanf("%d%d%d",&L,&R,&C)!=EOF) { getchar(); if(L==0&&R==0&&C==0) break; flag1=0; flag2=0; for(i=1; i<=L; i++) { for(j=1; j<=R; j++) { for(k=1; k<=C; k++) { scanf("%c",&maze[i][j][k]); if(!flag1||!flag2) { if(maze[i][j][k]=='S') { flag1=1; zb=i; xb=j; yb=k; } if(maze[i][j][k]=='E') { flag2=1; ze=i; xe=j; ye=k; } } } getchar(); } if(i<L) getchar(); } flag=0; time=bfs(zb,xb,yb); if(flag) printf("Escaped in %d minute(s).\n",time); else printf("Trapped!\n"); } return 0; }