bfs_迷宮問題 POJ - 3984
阿新 • • 發佈:2018-12-02
題目:
定義一個二維陣列:
int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, };
它表示一個迷宮,其中的1表示牆壁,0表示可以走的路,只能橫著走或豎著走,不能斜著走,要求程式設計序找出從左上角到右下角的最短路線。
Input
一個5 × 5的二維陣列,表示一個迷宮。資料保證有唯一解。
Output
左上角到右下角的最短路徑,格式如樣例所示。
Sample Input
0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0
Sample Output
(0, 0) (1, 0) (2, 0) (2, 1) (2, 2) (2, 3) (2, 4) (3, 4) (4, 4)
題目大意:
有一個迷宮,要求探索能否到達終點,如果可以的話輸出路徑
演算法:
bfs 佇列
程式碼:
#include<bits\stdc++.h> #include<cstdio> #include<iostream> using namespace std; struct node { int x; int y; int f; }; struct node que[2501]; //一共最多有2500個元素 int a[51][51],b[51][51]; //a是儲存迷宮的陣列 b是標記陣列 void print(int s) //遞迴輸出 { if(que[s].f!=-1) { print(que[s].f);//根據查詢前一個的位置來遞迴 cout<<"("<<que[s].x<<", "<<que[s].y<<")"<<endl; } } int main() { int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}}; //方向陣列 用來遍歷四個方向 int head,tail; int i,j,k,p,q,tx,ty,flag; for(i=0;i<5;i++) for(j=0;j<5;j++) cin>>a[i][j]; //輸入迷宮資訊 head=tail=1; que[tail].x=0; que[tail].y=0; //迷宮起點入隊 que[tail].f=-1; //起點的father標記為-1 便於遞迴輸出路徑時使用 tail++; b[0][0]=1; //標記這個點已經走過 flag=0; //flag在判斷終止時使用 while(head<tail) { for(k=0;k<4;k++) { tx=que[head].x+next[k][0]; ty=que[head].y+next[k][1]; //四個方向 if(tx<0||tx>4||ty<0||ty>4) continue; //越界 if(a[tx][ty]==0&&b[tx][ty]==0) //這個點之前沒有走過 並且 是路 { b[tx][ty]=1; //標記 que[tail].x=tx; que[tail].y=ty; que[tail].f=head; //入隊 tail++; } if(tx==4&&ty==4) { flag=1; break; //到達終點 } } if(flag==1) break; head++; //這個點已經探索完了 出隊 } cout<<"(0, 0)"<<endl; if(flag==1) print(head); cout<<"(4, 4)"; return 0; }
解析:
這道題,要求輸出路徑,於是決定使用bfs演算法,採用佇列,可以儲存路徑。
que[].f 用來儲存這個元素的父節點,也就是說-儲存這個節點是從哪一個節點探索而來的。
當探索到終點後,使用自定義的遞迴print函式輸出路徑。
如果這個點的父親不是-1(也就是程式碼最開始,起點入隊時,標記的que[tail].f=-1)那麼就遞迴他的父親節點,知道這個元素的父親節點是起點,那麼就輸出他本身,這也就是為什麼要單獨輸出起點。
至於為什麼單獨輸出終點座標是因為: 在判斷flag==1後就直接break了,沒有進行head++。
說完了路徑再來說 bfs 總的來說我對bfs的使用沒有dfs的順手
每探索完四個方向,這個時候就要出隊,這個地方的出隊並不是c++佇列的真正出隊,他還是儲存在了原本的陣列中,只是我們認為他已經出隊了。