寬度優先搜索(BFS,Breadth-First Search)也是搜索的手段之一,與深度優先搜索類似,從某個狀態出發搜索所有可以到達的狀態。
與深度優先搜索的不同之處在於搜索的順序,寬度優先搜索總是先搜索距離初始狀態最近的狀態。也就是說,它是按照開始狀態→只需一次轉移就能到達的所有狀態→只需2次就可以到達的所有狀態→…按照這樣的順序進行搜索。對於同一個狀態,寬度優先搜索只經過一次,因此時間復雜度為O(狀態數×轉移的方式)。

深度優先搜索利用了棧進行計算,而寬度優先搜索則利用了隊列進行計算。搜索時首先將狀態添加進隊列里,此后從隊列的最前端不斷取出狀態,把從該狀態可以轉移到的狀態尚未訪問過的部分加入到隊列中,如此往復,直至隊列被取空或找到了問題的解。通過觀察這個隊列,我們就可以知道所有的狀態都是按照距初始狀態由近及遠的順序遍歷的。
例題:
迷宮的最短路徑
給定一個大小為N×M的迷宮。迷宮由通道和牆壁組成,每一步可以向鄰接的上下左右四個的通道移動。請求出從起點到終點所需的最小步數。請注意,本題假定從起點一定可以移動到終點。(N,M≤100)('#', '.' , 'S', 'G'分別表示牆壁、通道、起點和終點)
輸入:
10 10
#S######.#
......#..#
.#.##.##.#
.#........
##.##.####
....#....#
.#######.#
....#.....
.####.###.
....#...G#
輸出:
22
代碼:
#include<iostream> #include<queue> using namespace std; const int INF = 100000000, maxn = 105; typedef pair<int, int> P;//可以使用結構體 char maze[maxn][maxn]; int n, m, sx, sy, gx, gy,d[maxn][maxn];//到各個位置的最短距離的數組 int dx[4] = { 1,0,-1,0 }, dy[4]= { 0,1,0,-1 };//4個方向移動的向量 int bfs()//求從(sx,sy)到(gx,gy)的最短距離,若無法到達則是INF { queue<P> que; for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) d[i][j] = INF;//所有的位置都初始化為INF que.push(P(sx, sy));//將起點加入隊列中 d[sx][sy] = 0;//並把這一地點的距離設置為0 while (que.size())//不斷循環直到隊列的長度為0 { P p = que.front();// 從隊列的最前段取出元素 que.pop();//取出后從隊列中刪除該元素 if (p.first == gx&&p.second == gy) break; for (int i = 0; i < 4; i++)//四個方向的循環 { int nx = p.first + dx[i],ny = p.second + dy[i];//移動后的位置標記為(nx,ny) if (0 <= nx&&nx < n && 0 <= ny&&ny < m&&maze[nx][ny] != '#'&&d[nx][ny] == INF)//判斷是否可以移動以及是否訪問過(即d[nx][ny]!=INF) { que.push(P(nx, ny));//可以移動,添加到隊列 d[nx][ny] = d[p.first][p.second] + 1;//到該位置的距離為到p的距離+1 } } } return d[gx][gy]; } int main() { cin >> n >> m; sx = 0, sy = 1, gx = 9, gy = 8;//起點和終點坐標 for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) cin >> maze[i][j]; cout << bfs() << endl; return 0; }
寬搜和深搜一樣,都會生成能夠所有遍歷到的狀態,因此需要對所有狀態處理時使用寬度優先搜索也是可以的。但是遞歸函數可以很簡短地編寫,而且狀態的管理也更簡單,所以大多數情況下都是用深搜實現。反之,在求取最短路時深度優先搜索需要反復經歷同樣的狀態,所以此時還是用寬度優先搜索為好。
