迷宫问题是一个经典的bfs问题,bfs相比于dfs,代码的实现上较为复杂,因此迷宫问题对于初学者而言是有一定难度的。而在这里,笔者将对迷宫问题做出比较详细的解释。
由于本篇博客侧重于对迷宫问题的讲解,所以对于一些其它概念将做一些省略,在看本篇博客前你需要掌握:
1、BFS的基本概念与思路
2、数据类型queue的概念与使用方法
3、pair的使用方法
4、memset函数的使用方法
如果对上面4点知识点还有不了解的地方,可以先点个收藏,然后在了解相关知识点后再来看本篇博客。(要回来哦)
上题目!!!!
(附上oj地址:献给阿尔吉侬的花束)
阿尔吉侬是一只聪明又慵懒的小白鼠,它最擅长的就是走各种各样的迷宫。
今天它要挑战一个非常大的迷宫,研究员们为了鼓励阿尔吉侬尽快到达终点,就在终点放了一块阿尔吉侬最喜欢的奶酪。
现在研究员们想知道,如果阿尔吉侬足够聪明,它最少需要多少时间就能吃到奶酪。
迷宫用一个 R×C 的字符矩阵来表示。
字符 S 表示阿尔吉侬所在的位置,字符 E 表示奶酪所在的位置,字符 # 表示墙壁,字符 . 表示可以通行。
阿尔吉侬在 1 个单位时间内可以从当前的位置走到它上下左右四个方向上的任意一个位置,但不能走出地图边界。
输入格式
第一行是一个正整数 T,表示一共有 T 组数据。
每一组数据的第一行包含了两个用空格分开的正整数 R 和 C,表示地图是一个 R×C 的矩阵。
接下来的 R 行描述了地图的具体内容,每一行包含了 C 个字符。字符含义如题目描述中所述。保证有且仅有一个 S 和 E。
输出格式
对于每一组数据,输出阿尔吉侬吃到奶酪的最少单位时间。
若阿尔吉侬无法吃到奶酪,则输出“oop!”(只输出引号里面的内容,不输出引号)。
每组数据的输出结果占一行。
数据范围
1<T≤10,
2≤R,C≤200
输入样例
3
3 4
.S..
###.
..E.
3 4
.S..
.E..
....
3 4
.S..
####
..E.
输出
5
1
oop!
在理解了题目后,让我们来看看代码的逐句分析
在这里提醒,代码的理解难度在于对pair的不理解导致first,second无法理解以及对于bfs搜索pop与push数据的时机与条件的把握无法理解,
#include<iostream>
#include<queue> //bfs需要用到用到队列
#include<cstring> //下方memset函数需要用到
using namespace std;
typedef pair<int, int>pii; //把pair的定义方式简化,pair代表一个点坐标,pii作用就像int,代表pair数据类型(pair.first,pair.second)
const int N = 210;
char a[N][N]; //用于储存迷宫
int dis[N][N]; //用于记录从起点到这个点的最短距离
void bfs(pii start) //bfs函数的实现,需要把起点作为形参数输入
{
queue<pii> q; //定义一个pair类型的队列,每个pair的first和second代表a[first][second]
q.push(start); //先把起点push进队列
while (!q.empty()) //开始广度优先搜索
{
pii u = q.front(); //定义一个临时变量存下队列的第一个pair
q.pop(); //把队列的第一个数删除
int dx[4] = { -1,0,1,0 };
int dy[4] = { 0,1,0,-1 };
for (int i = 0; i < 4; i++) //借用dx和dy来访问a[u.first][u.second]上下左右的四个点
{
/*这里用4次循环,借x与y来访问a[u.first][u.second]上下左右4个点*/
int x = u.first + dx[i];
int y = u.second + dy[i];
if (a[x][y] == '#') //遇到墙就返回
continue;
if (a[x][y] == '.') //如果不是墙
{
dis[x][y] = dis[u.first][u.second]+1; //记录下从起点到a[x][y]的最小步数
a[x][y] = '#'; //代表这个点已经被记录了,
q.push({ x,y }); //把这个(x,y)点push进队列,用来等会搜索这个点上下左右的4个点
}
if (a[x][y] == 'E') //搜索到E就代表找到了终点,结束搜索
{
cout << dis[u.first][u.second] + 1 << endl; //输出从起点到这个点的最小步数
return; //结束bfs函数
}
}
}
cout << "opp!" << endl; //如果直到队列为空都没有找到E,就说明迷宫无解
}
int main()
{
int t;
cin >>t ;
while (t--)
{
memset(a, '#', sizeof(a)); //迷宫的每个点初始化为#
memset(dis, 0, sizeof(dis)); //把距离数组的每一个值初始化为0
int n, m;
pii start; //定义起点
cin >> n >> m;
for(int i=1;i<=n;i++)
for (int j = 1; j <= m; j++)
{
cin >> a[i][j];
if (a[i][j] == 'S') //寻找起点,记录下起点
start.first = i, start.second = j;
}
bfs(start); //代入起点调用bfs函数
}
return 0;
}
到这里,迷宫问题的解析就结束了,很简单吧?( 你胡说 )
作者:Avalon Demerzel,是个正在不断努力学习的小白,如果觉得博客不错,就来个三连吧(点个赞也行)。让我们一起进步。