相关题连接:
一本通:http://ybt.ssoier.cn:8088/problem_show.php?pid=1215
小白菜OJ:http://caioj.cn/problem.php?id=1037
一、DFS写法:
问题一:迷宫是否能走通?(http://ybt.ssoier.cn:8088/problem_show.php?pid=1215 )
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 int n; 5 char a[200][200]={0};//用于存放迷宫数据,.为可走,#为不可走 6 int book[200][200];//用于标记该点是否被访问,0为未被访问,1为已经访问 7 int next[4][2]={{0,-1},{-1,0},{0,1},{1,0}};//存储下一步坐标累加数 8 int stx, sty, edx, edy;//分别代表迷宫初始位置、目标位置坐标 9 bool f;//标记迷宫是否能走通 10 void dfs(int x, int y) 11 { 12 //如果到达目标坐标,则打印输出,递归出口 13 if(x==edx&&y==edy) { 14 f=true; 15 } 16 //尝试四方向的邻居坐标 17 for(int i=0; i<4; i++) 18 { 19 //计算下一个点的坐标 20 int nx=x+next[i][0]; 21 int ny=y+next[i][1]; 22 23 if(nx<0 || nx>n-1 || ny<0 || ny>n-1) continue;//判断是否越界 24 if(book[nx][ny]==0 && a[nx][ny]=='.') 25 { 26 book[nx][ny]=1;//试探 27 dfs(nx, ny); 28 //book[nx][ny]=0;//回溯 注意此处不需要回溯,否则就会超时 29 } 30 } 31 } 32 int main() 33 { 34 int k; 35 scanf("%d",&k); 36 while(k--) 37 { 38 f=false;//刚开始假定迷宫走不通 39 memset(book,0,sizeof(book)); //book初始化为0 40 scanf("%d",&n); 41 for(int i=0; i<n; i++) 42 for(int j=0; j<n; j++) 43 scanf(" %c",&a[i][j]);//特别注意这个地方%c前有个空格 原因:https://blog.csdn.net/hx1043116928/article/details/79736723 44 scanf("%d%d",&stx,&sty); 45 scanf("%d%d",&edx,&edy); 46 book[stx][sty]=1;//设定初始值为不可访问,避免形成回路 47 dfs(stx,sty); //从出发点开始,第一步走起 48 49 if(!f)printf("NO "); 50 else printf("YES "); 51 } 52 return 0; 53 }
问题二:有多少种走法?
问题三:输出每条走法?
问题四:输出最短路径数?(http://bbs.codeaha.com/problem-12032.html)
1 #include <cstdio> 2 int a[51][51],book[51][51]; 3 int next[4][2]= {{0,-1},{-1,0},{0,1},{1,0}};//这里一定要和数学上的坐标进行区分,x,y分别代表行和列 4 int n, m;//n行m列迷宫 5 int min=999999999;//用于存放最短步数,并设定min初始值为一个较大值 6 int stx,sty,edx,edy;//分别代表迷宫初始位置、目标位置坐标 7 bool f=false;//刚开始假定迷宫走不通 8 void dfs(int x,int y,int step) { 9 int nx,ny;//---->>>>注意这一行一定只能写在dfs内<<<<<----- 10 if(x==edx&&y==edy) { 11 f=true; 12 if(step<min) { 13 min=step; 14 } 15 return ;//判断边界的返回不能丢 16 } 17 for(int i=0; i<=3; i++) { 18 nx=x+next[i][0]; 19 ny=y+next[i][1]; 20 if(nx<1||nx>n||ny<1||ny>m) {//判断是否越界 21 continue; 22 } 23 if(book[nx][ny]==0&&a[nx][ny]==0) { 24 book[nx][ny]=1; 25 dfs(nx,ny,step+1); 26 book[nx][ny]=0;//收回不能丢 27 } 28 } 29 } 30 int main() { 31 scanf("%d%d",&n,&m); 32 for(int i=1; i<=n; i++) { 33 for(int j=1; j<=m; j++) { 34 scanf("%d",&a[i][j]); 35 } 36 } 37 scanf("%d%d%d%d",&stx,&sty,&edx,&edy); 38 book[stx][sty]=1;//这里就和全排列有点不一样,因为这里进去之后就要发生改变,而全排列进去之后不改变 39 dfs(sty,sty,0); 40 if(!f)printf("No Way!"); 41 else printf("%d ",min); 42 return 0; 43 }
二、BFS写法:
问题一:是否能走通?(http://ybt.ssoier.cn:8088/problem_show.php?pid=1215)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int k, n, ha, la, hb, lb; 4 char mp[105][105]; 5 int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//用二维数组标记上下左右坐标变化 6 bool ans; //答案 7 struct node{ //结构体来表示每个位置的坐标 8 int x, y; 9 }; 10 node que[10005];//结构体数组模拟队列 11 int f, r; //队首队尾 12 void bfs(){ 13 f=r=1; //初始化队首队尾为1 14 que[r].x=ha, que[r].y=la, mp[ha][la]='#';//起始点坐标入队,更改状态防止重复访问 15 while(f<=r){ 16 node t; //临时变量存放队首信息 17 t.x=que[f].x, t.y=que[f].y; 18 if(t.x==hb && t.y==lb){ //如果找到目标退出循环 19 ans=1; 20 break; 21 } 22 for(int i=0; i<4; i++){ //以队首位置 上下左右四个方向遍历 23 int nx=t.x+dir[i][0]; 24 int ny=t.y+dir[i][1]; 25 if(nx>=0 && nx<n && ny>=0 && ny<n && mp[nx][ny]=='.'){//判断是否符合入队条件 26 mp[nx][ny]='#'; //更改状态 27 r++; //队尾位置后移为入队做准备 28 que[r].x=nx; //行号入队 29 que[r].y=ny; //列号入队 30 } 31 } 32 f++; //队首出队 33 } 34 } 35 int main() 36 { 37 cin>>k; 38 while(k--){ 39 cin>>n; 40 for(int i=0; i<n; i++) 41 cin>>mp[i]; 42 cin>>ha>>la>>hb>>lb; 43 ans=0; 44 bfs(); 45 if(ans)cout<<"YES"<<endl; 46 else cout<<"NO"<<endl; 47 } 48 return 0; 49 }
问题二:最短步骤数(题目连接http://ybt.ssoier.cn:8088/problem_show.php?pid=1252)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int r, c; 4 char mp[45][45]; 5 struct node{ 6 int x, y, step; 7 }; 8 int fx, fy, fstep; 9 node que[2500]; 10 int front, rear; 11 int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}}; 12 void bfs() 13 { 14 front=rear=1; 15 que[rear].x=0; que[rear].y=0; //初始位置入队 16 que[rear].step=1; 17 mp[0][0]='#'; 18 while(front<=rear){ 19 fx=que[front].x; fy=que[front].y; fstep=que[front].step; //获取队首信息 20 if(fx==r-1 && fy==c-1){ 21 cout<<fstep<<endl; 22 break; 23 } 24 for(int i=0; i<4; i++){ 25 int nx=fx+dir[i][0]; 26 int ny=fy+dir[i][1]; 27 if(nx>=0 && nx<r && ny>=0 && ny<c && mp[nx][ny]=='.'){ 28 mp[nx][ny]='#'; 29 rear++; //队尾位置后移准备入队 30 que[rear].x=nx; //入队 31 que[rear].y=ny; //入队 32 que[rear].step=fstep+1; //步数加1 33 } 34 } 35 front++; //队首后移出队 36 } 37 } 38 int main() 39 { 40 cin>>r>>c; 41 for(int i=0; i<r; i++)cin>>mp[i]; 42 bfs(); 43 return 0; 44 }
问题三:最少需要走的步数(同问题二)(http://ybt.ssoier.cn:8088/problem_show.php?pid=1254)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n, m; 4 char mp[105][105]; 5 int sx, sy, tx, ty; 6 struct node{ //结构体定义位置坐标和起点开始步骤 7 int x, y, step; 8 }; 9 int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; //二维数组定义上下左右方向位移量 10 node que[10010]; //结构体数组存放队列 11 int f, r; //队首和队尾定义 12 void bfs(){ 13 f=r=1; //队列初始化 14 que[r].x=sx; que[r].y=sy; que[r].step=0; mp[sx][sy]='#';//初始位置入队 15 while(f<=r){ 16 int fx=que[f].x, fy=que[f].y, fs=que[f].step;//获取队首信息 17 if(fx==tx && fy==ty){//判断是否到达目标 18 cout<<fs; 19 break; 20 } 21 for(int i=0; i<4; i++){//遍历四个方向 22 int nx=fx+dir[i][0]; 23 int ny=fy+dir[i][1]; 24 if(nx>=0 && nx<n && ny>=0 && ny<m && (mp[nx][ny]=='.' || mp[nx][ny]=='T')){//判断是否满足入队条件 ,注意此处终点排除‘T’ 25 mp[nx][ny]='#';//更改状态避免重复入队 26 r++;//队尾后移准备入队 27 que[r].x=nx;//入队 28 que[r].y=ny; 29 que[r].step=fs+1;//步骤加1 30 } 31 } 32 f++;//队首后移出队 33 } 34 } 35 int main() 36 { 37 cin>>n>>m; 38 for(int i=0; i<n; i++) 39 cin>>mp[i]; 40 for(int i=0; i<n; i++) 41 for(int j=0; j<m; j++){ 42 if(mp[i][j]=='S'){ 43 sx=i; sy=j; 44 } 45 if(mp[i][j]=='T'){ 46 tx=i; ty=j; 47 } 48 } 49 bfs(); 50 return 0; 51 }
问题四:输出最短路径(http://ybt.ssoier.cn:8088/problem_show.php?pid=1255)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int maze[5][5]; 4 int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; 5 struct node{ //结构体表示位置坐标,以及该位置是从哪个点过来的 6 int x, y, from; 7 }; 8 node que[30]; //结构体数组来表示队列 9 int f, r; //队首队尾 10 void pr(int p){ //递归顺序打印路线 11 if(p==0) 12 return; 13 pr(que[p].from); 14 cout<<"("<<que[p].x<<", "<<que[p].y<<")"<<endl; 15 } 16 void pr2(){ 17 for(int i=f; i ; i=que[i].from) //逆着打印路线和pr()函数对比 18 cout<<"("<<que[i].x<<", "<<que[i].y<<")"<<endl; 19 } 20 void bfs() 21 { 22 f=r=1;//队列初始 23 que[r].x=0; que[r].y=0; que[r].from=0; maze[0][0]=1; //起始点入队 24 while(f<=r){ 25 int fx=que[f].x; //获取队首信息 26 int fy=que[f].y; //获取队首信息 27 if(fx==4 && fy==4)pr(f); //如果到达目标打印路径 28 for(int i=0; i<4; i++){ 29 int nx=fx+dir[i][0]; 30 int ny=fy+dir[i][1]; 31 if(nx>=0 && nx<5 && ny>=0 && ny<5 && maze[nx][ny]==0){ 32 maze[nx][ny]=1; 33 r++; //队尾后移准备入队 34 que[r].x=nx; //入队 35 que[r].y=ny; //入队 36 que[r].from=f; //入队坐标的爸爸是谁 37 } 38 } 39 f++; 40 } 41 } 42 int main() 43 { 44 for(int i=0; i<5; i++) 45 for(int j=0; j<5; j++) 46 cin>>maze[i][j]; 47 bfs(); 48 return 0; 49 }