白书训练指南上的第一道基础题,因为它在搜索中引入了超级源点,所以我自己试着做了一下,真的宛如发现新大陆一般,图论的建图技巧真的是在整个图论领域都十分适用啊。
因为UVa的尿性,写完去搜一下题解,居然有很多题解都是两次 bfs ……真是笑了
题意:
一个起火的迷宫,有很多起火的地点,给你初始位置,和起火地点,你的逃跑速度和火焰蔓延速度相等,问你能否跑出迷宫,若能,输出最短时间。
思路:
网上那些两遍bfs的应该是先一遍bfs处理出火焰蔓延到每一个格子的最短时间,在自己bfs时间加个时间大小判断的限制。
然而实际上,我们溶入超级源点的思路,然所有点一起开始跑,在同一个时间内,让所有火焰先跑,并加以标记,而人则把火焰和墙壁一起处理,避而不走。
AC Code
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <string>
#include <vector>
using namespace std;
const int maxn = 1010;
int row, col, st, en;
char mat[maxn][maxn];
bool vis[maxn][maxn];
int dx[] = { 0, -1, 0, 1 };
int dy[] = { -1, 0, 1, 0 };
struct node {
int x, y;
int time;
bool is_fire;
node() {}
node(int _x, int _y, int _time, bool _fire)
: x(_x)
, y(_y)
, time(_time)
, is_fire(_fire)
{
}
} tmp;
queue<node> que;
int bfs()
{
memset(vis, 0, sizeof vis);
vis[st][en] = true;
int x, y, time;
bool is_fire;
while (!que.empty()) {
tmp = que.front();
que.pop();
x = tmp.x, y = tmp.y, time = tmp.time, is_fire = tmp.is_fire;
if (!is_fire && (x == 0 || x == row - 1 || y == 0 || y == col - 1))
return time + 1;
for (int i = 0; i < 4; i++) {
int xx = x + dx[i];
int yy = y + dy[i];
if (xx >= 0 && xx < row && yy >= 0 && yy < col && !vis[xx][yy] && mat[xx][yy] != '#') {
if (is_fire) {
mat[xx][yy] = 'F';
que.push(node(xx, yy, time + 1, true));
} else if (mat[xx][yy] == 'F')
continue;
else
que.push(node(xx, yy, time + 1, false));
vis[xx][yy] = true;
}
}
}
return -1;
}
int main()
{
int T;
scanf("%d", &T);
while (T--) {
scanf("%d %d", &row, &col);
while (!que.empty())
que.pop();
for (int i = 0; i < row; i++)
scanf("%s", mat[i]);
for (int i = 0; i < row; i++)
for (int j = 0; j < col; j++) {
if (mat[i][j] == 'F')
que.push(node(i, j, 0, true));
else if (mat[i][j] == 'J')
st = i, en = j;
}
que.push(node(st, en, 0, false));
int ans = bfs();
if (ans == -1)
puts("IMPOSSIBLE");
else
printf("%d\n", ans);
}
return 0;
}