迷宮的最短路徑【BFS】

迷宮的最短路徑
時間限制:1000 ms | 內存限制:65535 KB
難度:3
描述:
給定一個大小爲N * M 的迷宮。迷宮由通道和牆壁組成,每一步可以向鄰接的上下左右四格的通道移動。請求出從起點到終點所需的最小步數。請注意,本題假定從起點一定可以移動到終點 。
限制條件: N , M<=100 。( # . S G 分別代表 牆壁、通道、起點和終點。)

輸入:
第1行:兩個空格分隔的整數:n和m
輸出入n行m列的迷宮圖

輸出:
輸出一個整數,表示從起點到終點所需的最小步數。

樣例輸入:
10 10


在這裏插入圖片描述

樣例輸出:
22

剛剛完成深度優先搜索的學習,理解記住兩個經典例子部分和問題Lake Counting基本上便能理解DFS了。
之後,又學習了廣度優先搜索【BFS】,起初自己寫的時候,利用四個分開的循環分別遞歸,雖然最後也出結果了,但是看完《程序設計競賽》裏面的答案才知道自己是多笨。。。。hhhhh
俺還有電子版哦,需要的可私,或者評論留郵件。。。emmm

寬度優先搜索按照距開始狀態由近及遠的顧序進行搜索,因此可以很容易地用來求最短路徑。最少操作之類問題的答案。這個問題中,狀態僅僅是目前所在位置的座標.因此可以構造成pair.或者編碼成int來表達決態。當狀態更加複雜時,就需要村裝成一個類來表示狀態了。 轉移的方式爲四方向移動,狀態數與迷宮的大小是相等的。

寬度優先搜索中.只要將已經訪問過的狀態用標記管理起來。就可以很好地做到由近及遠的搜索。這個問題中由於要求最短距離,不妨用 d [ i ] [ j ] 數組把最短距離保存起來。初始時用充分大的常數INF來初始化它,這樣尚未到達的位置就是INF,也就同時起到了標記的作用。

雖然到達終點時就會停止搜索,可如果繼續下夫直到隊列爲空的話,就可以計算出到各個位冒的最短距離。此外,如果搜索到最後. 依然爲INF的話,便可得知這個位置就是無法從起點到達的位置

在今後的程序中,使用像INF這樣充分大的常數的情況還很多。不把INF當作例外,而是直接參與普通運算的情況也很常見。這種情況下,如果INF過大就可能帶來溢出的危險。

#include<stdio.h>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std; 
typedef pair<int , int> p;
const int INF=99666; 
char map[1000][1000];
int d[1000][1000];         //標記數組 
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int n,m,sx,sy,gx,gy;
int bfs()
{
	queue<p>que;
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
		{
			d[i][j]=INF;
		}
	que.push(p(sx,sy));	
	d[sx][sy]=0;
	while(que.size())
	{
		p q=que.front();
		que.pop();
		if(q.first==gx&&q.second==gy)break;
		//四個方向
		for(int i=0;i<n;i++)
		{
			int nx=q.first+dx[i];
			int ny=q.second+dy[i];
			//條件判斷,是否可以進行寬度優先搜索;
			if(nx>=0&&nx<n&&ny>=0&&ny<m&&map[nx][ny]!='#'&&d[nx][ny]==INF)
			{
				que.push(p(nx,ny));
				d[nx][ny]=d[q.first][q.second]+1;
			} 
		}	 
	}
	return d[gx][gy];
}
int main()
{
	cin >> n >> m;
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
		{
			cin >> map[i][j];  
			if(map[i][j]=='S'){sx=i;sy=j;}
			if(map[i][j]=='G'){gx=i;gy=j;}
		} 
	int s=bfs();	
	cout << s << endl;
		for(int i=0;i<n;i++,cout << endl)
		for(int j=0;j<m;j++)
		{
			if(d[i][j]!=INF)printf("%3d",d[i][j]);
			else printf("   ");
		} 
	return 0;
}

寬度優先搜索與深度優先搜索一樣,都會生成所有能夠遍歷到的狀態,因此需要對所有狀態進行處理時使用寬度優先搜索也是可以的。但是遞歸函數可以很簡短地編寫,而且狀態的管理也更簡單,所以大多數情況下還是用深度優先搜索實現。反之,在求取最短路時深度優先搜索需要反覆經過同樣的狀態,所以此時還是使用寬度優先搜索爲好。

寬度優先搜索會把狀態逐個加入隊列,因此通常需要與狀態數成正比的內存空間。反之,探度優先搜索是與最大的遞歸深度成正比的。-般與狀態數相比,遞歸的深度並不會太大,所以可以認爲深度優先搜索更加節省內存。

改革尚未成功,同志仍需努力!!!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章