题目链接:UVa 11624 Fire!
要是把人和火一起考虑就会感觉很乱,可以分开考虑,然后计算某个边界点谁先到,人先到就表示人可以逃出去,然后取这些值中那个最小的,这里有一个问题,会不会在途中人和火相遇,然后人比火先到达某个边界点,仔细想想就会发现不会有这种情况,用反证法,如果相遇,那么某个边界点至少是人和火同时到。
所有火都需要都加入队列。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
struct Point
{
int x, y;
Point (int x, int y) : x(x), y(y) {};
Point(){};
};
const int MAX_N = 1000 + 10;
int vis1[MAX_N][MAX_N], vis2[MAX_N][MAX_N],dis1[MAX_N][MAX_N], dis2[MAX_N][MAX_N];
char _map[MAX_N][MAX_N];
int fx[4] = {0, 0, 1, -1};
int fy[4] = {1, -1, 0, 0};
int R, C;
queue <Point> Q;
void BFS1()
{
int dx, dy;
while(!Q.empty())
{
Point a = Q.front();
Q.pop();
for(int i = 0; i < 4; i++)
{
dx = a.x + fx[i], dy = a.y + fy[i];
if(dx >= 0 && dx < R && dy >= 0 && dy < C && _map[dx][dy] != '#' && !vis1[dx][dy])
{
dis1[dx][dy] = dis1[a.x][a.y] + 1;
vis1[dx][dy] = 1;
Q.push(Point(dx, dy));
}
}
}
}
void BFS2()
{
int dx, dy;
while(!Q.empty())
{
Point a = Q.front();
Q.pop();
for(int i = 0; i < 4; i++)
{
dx = a.x + fx[i], dy = a.y + fy[i];
if(dx >= 0 && dx < R && dy >= 0 && dy < C && _map[dx][dy] != '#' && !vis2[dx][dy])
{
dis2[dx][dy] = dis2[a.x][a.y] + 1;
vis2[dx][dy] = 1;
Q.push(Point(dx, dy));
}
}
}
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
memset(vis1, 0, sizeof(vis1)), memset(vis2, 0, sizeof(vis2));
vector <Point> fires;
Point Joe;
scanf("%d%d", &R, &C);
for(int i = 0; i < R; i++)
{
scanf("%s", _map[i]);
for(int j = 0; j < C; j++)
{
if(_map[i][j] == 'F')
fires.push_back(Point(i, j));
else if(_map[i][j] == 'J')
Joe.x = i, Joe.y = j;
}
}
int _size = fires.size();
for(int i = 0; i < _size; i++)
{
Q.push(fires[i]);
dis2[fires[i].x][fires[i].y] = 0;
vis2[fires[i].x][fires[i].y] = 1;
}
BFS2();
Q.push(Joe);
dis1[Joe.x][Joe.y] = 0;
vis1[Joe.x][Joe.y] = 1;
BFS1();
int ans = MAX_N * MAX_N;
for(int i = 0; i < R; i++)
{
if(vis1[i][0])
{
if(!vis2[i][0] || dis2[i][0] > dis1[i][0])
ans = min(ans, dis1[i][0]);
}
if(vis1[i][C - 1])
{
if(!vis2[i][C - 1] || dis2[i][C - 1] > dis1[i][C - 1])
ans = min(ans, dis1[i][C - 1]);
}
}
for(int j = 0; j < C; j++)
{
if(vis1[0][j])
{
if(!vis2[0][j] || dis2[0][j] > dis1[0][j])
ans = min(ans, dis1[0][j]);
}
if(vis1[R - 1][j])
{
if(!vis2[R - 1][j] || dis2[R - 1][j] > dis1[R - 1][j])
ans = min(ans, dis1[R - 1][j]);
}
}
if(ans == MAX_N * MAX_N)
printf("IMPOSSIBLE\n");
else
printf("%d\n", ans + 1);
}
return 0;
}