I.从你的全世界路过
题目描述:
输入描述:
输出描述:
示例:
思路:
双重最短路问题,可以使用两个 BFS 来求解,利用队列实现,分别求出毒气到达某点的最短时间和陈末到达某点的最短时间。特别要注意,毒气不止一个地方有,每次遍历都需要查找毒气的位置;而陈末的位置只有一个,找到后即可标记下来。
每次比较时间,若毒气的时间小于陈末到达的时间,则陈末可以走,直到出口。
AC代码如下:
#include <bits/stdc++.h>
#define PII pair<int, int>
#define ll long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1e3 + 5;
int n, m;
char mp[N][N];//地图数组
int a[N][N];//毒气到达该点的时间
int b[N][N];//陈末到达该点的时间
int sx, sy;//陈末的起点位置
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};//方向数组
int ans;//陈末走出迷宫时间
struct node{
int x;
int y;
int t;//时间
};
queue<PII> ta;//存放毒气的队列
queue<node> tb;//存在陈末的队列
//这里我将两个 bfs 放在一块写了
void bfs()
{
while (!ta.empty()){
//申请名为 u 的保存两个整数的pair容器
PII u = ta.front();//取出队首元素放入pair容器中
ta.pop();//删除队首元素
for (int i = 0; i < 4; i++){
//下一个点的坐标
int xx = u.first + dx[i], yy = u.second + dy[i];
//判断边界和墙壁
if (xx < 1 || yy < 1 || xx > n || yy > m || mp[xx][yy] == '#')
continue;
//不更新已经走过的位置
if (a[xx][yy] <= a[u.first][u.second] + 1)
continue;
//拓展后,符合条件的点放入队尾
ta.push({xx, yy});
//毒气到达该点的最短时间
a[xx][yy] = min(a[xx][yy], a[u.first][u.second] + 1);
}
}
//陈末的队列放入陈末的起点,时间初始化为0
tb.push({sx, sy, 0});
b[sx][sy] = 0;
ans = -1;
while (!tb.empty()){
//取出队首元素放入结构体中
node v = tb.front();
//用完删除队首元素
tb.pop();
//如果走到了边界
if (v.x == 1 || v.y == 1 || v.x == n || v.y == m ){
//且下一步时,人到达的时间小于毒气到达的时间
if (a[v.x][v.y] >= v.t + 1){
//将时间加一
ans = v.t + 1;
break;
}
}
//遍历下一个点
for (int i = 0; i < 4; i++){
int xx = v.x + dx[i], yy = v.y + dy[i];
if (xx < 1 || yy < 1 || xx > n || yy > m)
continue;
if (b[xx][yy] <= v.t + 1)
continue;
//如果没有毒气,且人到达的时间小于毒气到达的时间,放入队尾
if (mp[xx][yy] == '.' && v.t + 1 <= a[xx][yy]){
tb.push({xx, yy, v.t + 1});
//时间加一
b[xx][yy] = v.t + 1;
}
}
}
}
int main()
{
scanf("%d %d\n", &n, &m);
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
cin >> mp[i][j];
//将时间初始化尽量大
a[i][j] = b[i][j] = INF;
//找到陈末的起点
if (mp[i][j] == 'C'){
sx = i;
sy = j;
}
//找到毒气的位置,放入队列中,标记
if (mp[i][j] == '*'){
ta.push({i, j});
//初始化时间为0
a[i][j] = 0;
}
}
}
//调用BFS遍历
bfs();
if (ans == -1)
puts("NO");
else
printf("%d\n", ans);
return 0;
}