這個是BFS搜索的典型問題,好好整理一下:
給定一個迷宮,入口為左上角,出口為右下角,問是否有路徑從入口到出口,若有則輸出一條這樣的路徑。注意移動可以從上、下、左、右、上左、上右、下左、下右八個方向進行。迷宮輸入0表示可走,輸入1表示牆。易得可以用1將迷宮圍起來避免邊界問題。本題采用BFS算法給出解。注意,利用BFS算法給出的路徑必然是一條最短路徑。
input:
1
6 8
0 1 1 1 0 1 1 1
1 0 1 0 1 0 1 0
0 1 0 0 1 1 1 1
0 1 1 1 0 0 1 1
1 0 0 1 1 0 0 0
0 1 1 0 0 1 1 0
output:
YES
(1,1) (2,2) (3,3) (3,4) (4,5) (4,6) (5,7) (6,8)
基本思路:
采用BFS的思路,每個位置相當於一個結點,用BFS進行廣度搜索,相當於往外一環一環擴散的感覺,最后看能否達到出口的位置。
實現以及技巧:
1.基本的數據結構:相比對於一棵樹的BFS來說,這里的BFS中的Node是一個坐標,因此要自定義好結點,typedef struct Node{int x; int y;}Node;BFS里面要用到隊列,對基本的隊列的庫函數的聲明和使用要熟悉,Q.size() Q.push(Node) Q.front() 以及Q.pop()
2.關於path的問題:由於要存儲路徑信息,這里的path是一個二維的指針數組,注意這種聲明以及初始化的方式:聲明Node **path;初始化:
path=new Node*[MAXL];
for(i=0;i<=MAXL;i++)
{path[i]=new Node[MAXH];}
應該還有其他的表述方式,總之要會用一個,這里涉及到二維時候的指針還是挺麻煩的。
3.還要注意每次path的更新點的選擇問題,在每次元素入隊的時候,比如當前元素為now,檢查它周圍的8個點,讓沒有牆的點入隊,比如一個沒有牆的點是temp就在這個位置上更新,path[temp.x][temp.y]=now。
4.path輸出的問題也很重要,這個最好就記下來,就是遞歸輸出,比較典型,具體看代碼的outputpath函數。
5.考慮向周圍移動的時候:向周圍的8個點移動的時候可以先設置好一個二維數組:
Node move[8]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{-1,1},{-1,-1},{-1,1}};
之后一個循環,把對應的x y值加上去就好,這樣比較省事。注意結構體賦初值的時候也可以用這種小括號的形式:Node start={1,1};
6.還有一點容易忽略,想周圍移動的時候,已經探測過的點要做個標記,比如標記成-1或者類似的,這樣就不會繞回去了,否則有可能形成一個環。
7.還有其他的技巧,就是在地圖初始化的時候,在周圍加上一圈的圍牆,這樣在具體BFS的時候就不用再考慮邊界的問題了。
具體代碼如下:
//http://blog.csdn.net/that163/article/details/8069764 #include<iostream> #include<cstdio> #include<queue> #include<cstring> #define MAXH 20 #define MAXL 20 using namespace std; typedef struct Node{ int x; int y; }Node; //記錄地圖信息 int maze[MAXH][MAXL]; //記錄路徑信息 //Node*path[MAXH][MAXL]; Node **path; Node move[8]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{-1,1},{-1,-1},{-1,1}}; bool BFS(Node start,Node end) { int i; Node tempN; Node tempNM; queue<Node>Q; Q.push(start); maze[start.x][start.y]=-1; //while(tempN.x!=end.x&&tempN.y!=end.y&&Q.size!=0) while(Q.size()!=0) { tempN=Q.front(); Q.pop(); //遍歷8個方向全部的點 for(i=0;i<8;i++) { tempNM.x=tempN.x+move[i].x; tempNM.y=tempN.y+move[i].y; //若是移動之后的點 位置是0 表示可以通過 if(tempNM.x>=1&&tempNM.y>=1&&tempNM.x<=end.x&&tempNM.y<=end.y&&maze[tempNM.x][tempNM.y]==0) { //孩子結點入隊 Q.push(tempNM); //已經嘗試過的點標記成-1 maze[tempNM.x][tempNM.y]=-1; path[tempNM.x][tempNM.y]=tempN; } } } if(tempN.x==end.x&&tempN.y==end.y) {return true;} else {return false;} } void outputpath(Node end) { //可以遞歸輸出 Node temp=end; if(end.x==1&&end.y==1) { printf("(%d,%d)",end.x,end.y); return; } else { //取出指針的內容 temp=path[temp.x][temp.y]; outputpath(temp); if(temp.x!=1&&temp.y!=1) {printf("(%d,%d)",temp.x,temp.y);} } return; } int main() { freopen("in.txt","r",stdin); int hang,lie,N; int i,j; scanf("%d",&N); while(N--) { //輸入部分 scanf("%d%d",&hang,&lie); for(i=1;i<=hang;i++) { for(j=1;j<=lie;j++) { if(j==lie) { scanf(" %d",&maze[i][j]); } else { scanf("%d",&maze[i][j]); } } } Node start={1,1}; //注意結構體的這種用中括號來賦值的方式 Node end={hang,lie}; //二維指針數組的規定初始值的方式 //此時path是一個指向一維指針數組的指針 path=new Node*[MAXL]; for(i=0;i<=MAXL;i++) {path[i]=new Node[MAXH];} //調用BFS函數進行搜索 更新path矩陣信息 bool connect=BFS(start,end); if(connect) puts("YES"); else puts("NO"); //輸出路徑信息 outputpath(end); printf("(%d,%d)\n",6,8); } return 0; }