迷宮的最短路徑
給定一個大小為 N×M的迷宮。迷宮由通道和牆壁組成,每一步可以向鄰接的上下左右四格的通道移動。請求出從起點到終點所需的小步數。請注意,本題假定從起點一定可以移動到終點
限制條件:N,M<=100;
樣例輸入:N=10,M=10('#','.','S','G'分別表示牆壁,通道,起點和終點)
#S######.#
......#..#
.#.##.##.#
.#........
##.##.####
....#....#
.#######.#
....#.....
.####.###.
....#...G#
dfs分析:主要考慮當前應該怎么做,每到一個點下一步有上下左右四種情況,我們按順時針方向右下左上來進行計算,到新的一個點判斷是否走過以及有沒有障礙物,如果答案是確定的就可以繼續dfs。
#include <iostream> #include <cstdio> using namespace std; int p0,q0,p1,q1;//儲存起始點和終點的橫縱坐標 char a[100][100];//根據數據量自己調整 int book[100][100];//標記數組來判斷有沒有到達 int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};//分別儲存x,y坐標下一步的可能情況 int mini=99999;//先給最小路徑一個很大的初值 int n,m; void dfs(int x,int y,int step){ if(x==p1&&y==q1){ if(step<mini) mini=step; return ;//函數直接結束 } for(int k=0;k<4;k++){ int nx=x+next[k][0], ny=y+next[k][1];//枚舉下一步可能的橫縱坐標 if(nx<1||nx>n||ny<1||ny>m){//控制不越界 continue; } if(book[nx][ny]==0&&a[nx][ny]=='.'||book[nx][ny]==0&&a[nx][ny]=='G'){ //cout<<step<<endl; book[nx][ny]=1;//標記走過了 dfs(nx,ny,step+1); book[nx][ny]=0;//注意dfs后返回這一點為沒走過。 } } return ; } int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>a[i][j]; if(a[i][j]=='S'){ p0=i;q0=j; } if(a[i][j]=='G'){ p1=i;q1=j; } } } //cout<<p0<<q0<<p1<<q1<<endl; //if(a[2][1]=='.') cout<<"just a test \n"; book[p0][q0]=1;//標記起始點走過了 dfs(p0,q0,0); cout<<mini<<endl; return 0; }
BFS分析:同深搜選擇一個點之后不斷繼續往下深入不同,寬搜是記錄所有到達后步數相同的點,更適宜做最短路徑的問題。
#include <iostream> #include <cstdio> using namespace std; char a[100][100];//根據題意自己設定數據量 int book[100][100];//標記某點是否到達 int sx,sy,gx,gy;//起始點坐標 struct node{ int x; int y; int s;//s表示步數 }; node q[10000];//100*100的地圖隊列擴展最多是10000 int main(){ int head,tail;head=tail=1; //一開始清空隊列 int n,m; cin>>n>>m; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>a[i][j]; if(a[i][j]=='S'){ sx=i;sy=j; } if(a[i][j]=='G'){ gx=i;gy=j; } } } int next[4][2]={{1,0},{0,1},{-1,0},{0,-1}}; q[tail].x=sx;q[tail].y=sy;q[tail].s=0;//將起點數據壓入隊列 tail++; book[sx][sy]=1; int flag=0;//flag是為了找到最短路徑后跳出while循環用的 while(head<tail){ for(int k=0;k<4;k++){ int tx=q[head].x+next[k][0],ty=q[head].y+next[k][1]; //判斷是否越界 if(tx<1||tx>n||ty<1||ty>m) continue; if(book[tx][ty]==0&&a[tx][ty]!='#'){ q[tail].x=tx;q[tail].y=ty;q[tail].s=q[head].s+1; book[tx][ty]=1;tail++; } if(tx==gx&&ty==gy){ flag=1; break; } } if(flag) break; head++; } cout<<q[tail-1].s<<endl; return 0; }
總結一下,dfs和bfs都能都能生成所有能夠遍歷到的狀態,但是遞歸可以更尖端的編寫且管理起來更簡單,所以大多數情況還是用dfs實現,反之,bfs處理起最短路徑時更方便。
此外,dfs更加節省內存。