题目链接
题目详情
阿尔吉侬是一只聪明又慵懒的小白鼠,它最擅长的就是走各种各样的迷宫。
今天它要挑战一个非常大的迷宫,研究员们为了鼓励阿尔吉侬尽快到达终点,就在终点放了一块阿尔吉侬最喜欢的奶酪。现在研究员们想知道,如果阿尔吉侬足够聪明,它最少需要多少时间就能吃到奶酪。
迷宫用一个R×C的字符矩阵来表示。
字符S表示阿尔吉侬所在的位置,字符E表示奶酪所在的位置,字符#表示墙壁,字符.表示可以通行。
阿尔吉侬在 1 个单位时间内可以从当前的位置走到它上下左右四个方向上的任意一个位置,但不能走出地图边界。
输入格式
第一行是一个正整数T,表示一共有T组数据。
每一组数据的第一行包含了两个用空格分开的正整数 R 和 C,表示地图是一个 R×C 的矩阵。
接下来的R行描述了地图的具体内容,每一行包含了C个字符。字符含义如题目描述中所述。保证有且仅有一个 S 和 E。
输出格式
对于每一组数据,输出阿尔吉侬吃到奶酪的最少单位时间。 若阿尔吉侬无法吃到奶酪,则输出“oop!”(只输出引号里面的内容,不输出引号)。 每组数据的输出结果占一行。
数据范围
1<T≤10,
2≤R,C≤200
解题思路
很典型的一道bfs,这里用a[N][N]来存储整个地图,用dis[N][N]记录每个点到出发点(S)的最短距离。最开始,我们将整个a初始化为墙(#),dis初始化为0,然后i从1-n,j从1-m来存储地图,这时,每个图的周围都是墙(#),所以就不需要进行边界出界的处理,使问题更简单。
接着就是bfs函数,对于广度优先遍历,我们先让起点入队,然后判断队列是否为空,只要非空我们一直进行循环:队头出队,然后进行上下左右四个方向的遍历。
有三种情况:
- 如果是'#',不做处理;
- 如果是'.',该点入队,其dis的值更新为队头的dis+1,并把该点更新为'#';
- 如果是'E',到了终点,输出该点的dis值,应为队头的dis+1,如果循环到最后并没有到达E点,那么就是无法从S走到E,输出oop!即可。
AC代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define int long long
typedef pair<int, int> PII;
const int N = 210;
char a[N][N];
int dis[N][N];
void bfs(PII start)
{
queue<PII> q;
q.push(start);//起点入队
while (!q.empty())//对列非空一直循环
{
PII u = q.front();
q.pop();//队头出队
int dx[4] = { -1,0,1,0 };
int dy[4] = { 0,1,0,-1 };//上下左右四个方向用x,y数组控制
for (int i = 0; i < 4; i++)//遍历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] = '#';//走过的路变成墙
q.push({ x,y });//让(x,y)这点入队
}
//如果到了终点('E'),输出即可
if (a[x][y] == 'E')
{
cout << dis[u.first][u.second] + 1 << endl;
return;
}
}
}
cout << "oop!" << endl;
}
signed main()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
{
memset(a, '#', sizeof a);
memset(dis, 0, sizeof dis);
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;
a[i][j] = '#';
}
}
}
bfs(start);
}
return 0;
}