目錄
題目詳情
Description
給定一個大小爲 N * M 的迷宮。迷宮由通道和牆壁組成,每一步可以向鄰接的上下左右四格的通道移動。請求出從起點到終點所需的最小步數
限制條件:
N,M <= 100
Input
輸入兩個數字 N 和 M,分別表示迷宮的長和寬,用空格隔開
輸入代表迷宮的字符串,N 行 M 列,由 '#','~','S','G' 組成,分別表示牆壁,通道,起點,終點
Output
從起點到終點所需的最小步數
Sample Input
10 10 #S######.# ......#..# .#.##.##.# .#........ ##.##.#### ....#....# .#######.# ....#..... .####.###. ....#...G#
Sample Output
22
題解
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int INF=100000000;
const int MAX_N=100+5,MAX_M=100+5;
typedef pair<int,int> P; //把 pair看作結構體,typedef的用法,P就是該結構體的一個實例。該"結構體"內只有兩個元素
//輸入
char a[MAX_N][MAX_M]; //表示迷宮的字符串數組
int N,M; //迷宮的長寬
int sx,sy; //起點座標
int gx,gy; //終點座標
int d[MAX_N][MAX_M]; //存放到各個位置的最短距離的數組
//向四個方向移動的向量:右、上、左、下
int dx[4]={1,0,-1,0}; //dx[i]是向量的橫座標
int dy[4]={0,1,0,-1}; //dy[i]是向量的縱座標
//從(sx,sy)到(gx,gy)的最短距離。如果無法到達,則是INF
int bfs(){
queue<P> que;
for(int i=0;i<N;++i){
for(int j=0;j<M;++j){
d[i][j]=INF; //把所有位置的距離初始化爲INF
}
}
//將起點加入隊列,並把這一地點的距離設置爲0
que.push(P(sx,sy));
d[sx][sy]=0;
//不斷循環直到隊列爲空
while(que.size()){
//從隊列最前端取出元素
P p=que.front();
que.pop();
//如果取出的狀態已經是終點,結束搜索
if(p.first==gx && p.second==gy){
break;
}
//四個方向的循環
for(int i=0;i<4;++i){
//移動後的位置記爲 (nx,ny)
int nx=p.first+dx[i],ny=p.second+dy[i];
//判斷是否可以移動,是否已經訪問過該點(d[nx][ny]!=INF即爲訪問過)
if(0<=nx && nx<N && 0<=ny && ny<M && a[nx][ny]!='#' && d[nx][ny]==INF){
//如果能夠移動則加入隊列,且到該位置的距離變成到 p 的距離 +1
que.push(P(nx,ny));
d[nx][ny]=d[p.first][p.second]+1;
}
}
}
return d[gx][gy];
}
int main(){
scanf("%d%d",&N,&M);
for(int i=0;i<N;++i){
scanf("%s",a[i]);
}
for(int i=0;i<N;++i){
for(int j=0;j<M;++j){
if(a[i][j]=='S'){
sx=i;
sy=j;
}
if(a[i][j]=='G'){
gx=i;
gy=j;
}
}
}
int res=bfs();
printf("%d",res);
return 0;
}
本題中,狀態是目前所在位置的座標,可以構造成 pair 或者編碼成 int 來表達狀態。當狀態更加複雜時,需要封裝成一個類來表示
寬度優先搜索中,只要將已經訪問過的狀態用標記管理起來,就可以很好的做到由近及遠的搜索。本題要求最短距離,可用 d[N][M] 數組保存。初始化時用充分大的常數 INF 初始化它,這樣尚未到達的位置就是 INF,同時起到標記的作用
到達終點時就會停止搜索,如果繼續搜索下去直到隊列爲空,可以計算出到各個位置的最短距離。如果搜索到最後,d 依然是 INF,這個位置就無法從起點到達
寬度優先搜索
寬度優先搜索可以用來求最短路徑,最少操作之類的問題
對於同一個狀態,寬度優先搜索只經過一次,因此時間複雜度:O(狀態數 * 轉移的方式)
寬度優先搜索與深度優先搜索類似,從某個狀態出發,探索所有可以到達的狀態。不同之處在於,寬度優先搜索總是先搜索距離初始狀態近的狀態
深度優先搜索利用棧進行計算,寬度優先搜索則利用了隊列。搜索時首先將初始狀態加到隊列裏,此後從隊列的最前端不斷取出狀態,把從該狀態可以轉移到的狀態中尚未訪問過的部分加入隊列,如此往復,直至隊列爲空或找到了問題的解
寬度優先搜索會把狀態逐個加入隊列,通常需要與狀態數成正比的內存空間。反之,深度優先搜索與最大的遞歸深度成正比。一般與狀態數相比,遞歸的深度不會太大,所以可以認爲深度優先搜索更加節省內存