迷宫的最短路径【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;
}

宽度优先搜索与深度优先搜索一样,都会生成所有能够遍历到的状态,因此需要对所有状态进行处理时使用宽度优先搜索也是可以的。但是递归函数可以很简短地编写,而且状态的管理也更简单,所以大多数情况下还是用深度优先搜索实现。反之,在求取最短路时深度优先搜索需要反复经过同样的状态,所以此时还是使用宽度优先搜索为好。

宽度优先搜索会把状态逐个加入队列,因此通常需要与状态数成正比的内存空间。反之,探度优先搜索是与最大的递归深度成正比的。-般与状态数相比,递归的深度并不会太大,所以可以认为深度优先搜索更加节省内存。

改革尚未成功,同志仍需努力!!!
发布了16 篇原创文章 · 获赞 26 · 访问量 1149

猜你喜欢

转载自blog.csdn.net/qq_43514659/article/details/103480861