1. 程式人生 > 其它 >百鍊3752:走迷宮--棧實現dfs

百鍊3752:走迷宮--棧實現dfs

3752:走迷宮

總時間限制:
1000ms
記憶體限制:
65536kB
描述
一個迷宮由R行C列格子組成,有的格子裡有障礙物,不能走;有的格子是空地,可以走。
給定一個迷宮,求從左上角走到右下角最少需要走多少步(資料保證一定能走到)。只能在水平方向或垂直方向走,不能斜著走。
輸入
第一行是兩個整數,R和C,代表迷宮的長和寬。( 1<= R,C <= 40)
接下來是R行,每行C個字元,代表整個迷宮。
空地格子用'.'表示,有障礙物的格子用'#'表示。
迷宮左上角和右下角都是'.'。
輸出
輸出從左上角走到右下角至少要經過多少步(即至少要經過多少個空地格子)。計算步數要包括起點和終點。
樣例輸入
5 5
..###
#....
#.#.#
#.#.#
#.#..
樣例輸出
9


【分析】 本題用遞迴實現起來不方便,因此用一個結構模擬走迷宮的過程:
1 struct node {
2     int x,y;    //節點座標
3     int step;   //到達該節點需要的步數
4     node(int x,int y,int step) : x(x),y(y),step(step) {};
5 };

此處,node表示迷宮中的一個“節點”。

用棧實現dfs走迷宮的思想:(1) 將起始節點棧;

          (2) 將起始節點出棧,作為“當前所在的節點”

          (3) 將“當前所在的節點”所能到達的所有節點入棧(這便是下一步所有的路);

          (4) 棧頂節點出棧,作為下一步的“當前所在的節點”

          (5) 重複上述過程,直到走到終點。

由於棧後進先出的特點,因此每一個出棧作為“當前所在的節點”的節點一定是上一步剛剛入棧的節點(即上一步的“當前所在的節點”所能直接到達的某個下一
步的節點),因此棧實現的是dfs(而非bfs)。

【程式碼】
 1 #include <iostream>
 2 #include <stack>
 3 using namespace std;
 4 
 5 const int maxr = 45;
 6 const int maxc = 45;
7 char board[maxr][maxc]; 8 bool visited[maxr][maxc]; 9 int R,C; 10 int mov[4][2] = { {0,1},{0,-1},{1,0},{-1,0} }; 11 12 struct node { 13 int x,y; //節點座標 14 int step; //到達該節點需要的步數 15 node(int x,int y,int step) : x(x),y(y),step(step) {}; 16 }; 17 18 bool check(int x,int y) 19 { 20 if( x <= R && x >= 1 && y <= C && y >= 1 && board[x][y] == '.' 21 && !visited[x][y] ) 22 return true; 23 return false; 24 } 25 26 int dfs(int x,int y) 27 { 28 stack<node> s; 29 node start(x,y,1); 30 s.push(start); 31 32 //棧僅是工具,真正的動態dfs過程從while迴圈中才開始, 33 //從棧中取出一個節點,相當於確定了目前所在的節點 34 while( !s.empty() ) { 35 node cur = s.top(); 36 s.pop(); 37 38 //以下for迴圈把當前能到達的所有點入棧 39 for( int i=0; i<4; i++ ) { 40 int ix = cur.x + mov[i][0]; 41 int iy = cur.y + mov[i][1]; 42 if( !check(ix,iy) ) continue; 43 44 node nxt(ix,iy,cur.step+1); //創造下一個合法節點 45 46 //判斷:如果已經到目標點直接返回答案 47 if( nxt.x == R && nxt.y == C ) { 48 return nxt.step; //(1) 49 } 50 visited[nxt.x][nxt.y] = true; //不加這句,會導致已走過的節點多次入棧,造成死迴圈 51 //入棧了的節點今後一定都能訪問到,因此不用擔心漏掉"可走的路" 52 s.push(nxt); 53 } 54 } 55 56 return -1; //若棧中所有節點都已經取出,程式走到了此處(而不是在(1)處返回), 57 //說明終點無法走到 58 } 59 60 int main() 61 { 62 cin >> R >> C; 63 for( int i=1; i<=R; i++ ) { 64 for( int j=1; j<=C; j++ ) { 65 cin >> board[i][j]; 66 } 67 getchar(); //除行尾回車 68 } 69 int ans = dfs(1,1); 70 71 cout << ans << endl; 72 return 0; 73 }

本題使用bfs實現也可以,只需要把棧換成佇列就行了。