1. 程式人生 > >迷宮的最短路徑之BFS演算法

迷宮的最短路徑之BFS演算法

給定一個大小為N*M的迷宮,由通道('.')和牆壁('#')組成,其中通道S表示起點,通道G表示終點,每一步移動可以達到上下左右中不是牆壁的位置。試求出起點到終點的最小步數。(本題假定迷宮是有解的)(N,M<=100)

樣例輸入:

10 10

樣例輸出:

22

這道題目以及解法均來自《挑戰程式設計競賽(第2版)》第34頁-36頁;

個人覺得這個例題很好地表現了廣度優先搜尋是如何與佇列先進先出(FIFO)的思想聯絡起來的,通過不斷取得某個狀態後能夠達到的所有狀態並將其加入佇列, 並且由於佇列本身的特性先加入佇列的狀態總是先得到處理,這樣就達到了一個目的:總是先將需要轉移次數更少的狀態進行分析處理,換句話說就是總是取得了這個狀態的樹中更接近根部的節點,又或者是總是讓搜尋樹的廣度得到儘可能增加。

在這個問題中,找到從起點到終點的最短路徑其實就是一個建立佇列的過程:

1.從起點開始,先將其加入佇列,設定距離為0;

2.從佇列首端取出位置,將從這個位置能夠到達的位置加入佇列,並且讓這些位置的距離為上一個位置的距離加上1;

3.迴圈2直到將終點新增到佇列中,這說明我們已經找到了路徑;

注意到在這個過程中,每次處理的位置所對應的距離是嚴格遞增的,因此一旦找到終點,當時的距離就是最短距離;

同樣基於這個原因,搜尋可移動到的位置所使用的判斷條件中不僅僅是不碰牆壁、不超過邊界,還有一個就是沒有到達過,因為如果已經到達了這個位置,這說明已經有更短的路徑到達這個位置,這次到達這個位置的路徑是更差的,不可能得到更好的最終解。

原始碼:

#include <iostream>
#include <queue>
using namespace std;
const int MAX_N = 100;
const int MAX_M = 100;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> P;
char maze[MAX_N][MAX_M + 1];
int N, M;
int sx, sy; //起點的位置
int gx, gy; //終點的位置

int d[MAX_N][MAX_M];//儲存起點到某一點的距離
int dx[4] = { 1,0,-1,0 }, dy[4] = { 0,1,0,-1 }; //表明每次x和y方向的位移

void bfs()
{
	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()) //題目保證有路到終點,所以不用擔心死迴圈
	{
		P p = que.front(); que.pop();//彈出隊首元素
		int i;
		for (i = 0; i < 4; i++)
		{
			int nx = p.first + dx[i];
			int ny = p.second + dy[i];//移動後的座標
			//判斷可移動且沒到過
			if (0 <= nx&&nx < N
				&& 0 <= ny&&ny < M
				&&maze[nx][ny] != '#'
				&&d[nx][ny] == INF)//之前到過的話不用考慮,因為距離在佇列中遞增,肯定不會獲得更好的解
			{
				que.push(P(nx, ny));	//可以移動則設定距離為之前加一,放入佇列
				d[nx][ny] = d[p.first][p.second] + 1;
				if(nx==gx && ny==gy) break;

                        }
		}
		if(i!=4) break;
	}

}

int main()
{
	cin>>N>>M;
	for (int i = 0; i < N; i++)
		cin>>maze[i];
	for (int i = 0; i < N; i++)
		for (int j = 0; j < M; j++)
		{
			if (maze[i][j] == 'S')
			{
				sx = i; sy = j;
			}
			if (maze[i][j] == 'G')
			{
				gx = i; gy = j;
			}
		}
	bfs();
	cout<<d[gx][gy]<<endl;

	return 0;
}

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------