题解
两次BFS,第一次BFS求出火蔓延到每个位置所需的最小时间。
第二次BFS人物尝试上下左右移动,如果移动到当前位置的时间大于等于火蔓延到的时间则当前人会被烧到,方案不可行。
AC代码
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e3 + 10;
int dir[4][2] = { -1, 0, 1, 0, 0, -1, 0, 1 };
char g[N][N];
int f[N][N]; //火蔓延到的时间
bool vis[N][N];
int n, m, sx, sy;
struct node
{
int x, y, k;
};
void fire()
{
memset(f, 0x3f, sizeof(f));
queue<node> q;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
if (g[i][j] == 'F')
q.push({ i, j, 0 }), f[i][j] = 0;
while (!q.empty())
{
int x = q.front().x, y = q.front().y, k = q.front().k; q.pop();
++k;
for (int i = 0; i < 4; ++i)
{
int xx = x + dir[i][0], yy = y + dir[i][1];
if (xx >= 1 && xx <= n && yy >= 1 && yy <= m && g[xx][yy] == '.' && f[xx][yy] == INF) //火不会到INF
q.push({ xx, yy, k }), f[xx][yy] = k;
}
}
}
int BFS()
{
memset(vis, 0, sizeof(vis));
queue<node> q;
q.push({ sx, sy, 0 });
vis[sx][sy] = 1;
while (!q.empty())
{
int x = q.front().x, y = q.front().y, k = q.front().k; q.pop();
++k;
for (int i = 0; i < 4; ++i)
{
int xx = x + dir[i][0], yy = y + dir[i][1];
if (xx >= 1 && xx <= n && yy >= 1 && yy <= m)
{
if (g[xx][yy] == '.' && !vis[xx][yy] && k < f[xx][yy]) //当前时间火还没到
q.push({ xx, yy, k }), vis[xx][yy] = 1;
}
else
return k;
}
}
return -1;
}
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
int T;
cin >> T;
while (T--)
{
cin >> n >> m;
for (int i = 1; i <= n; ++i)
{
scanf("%s", g[i] + 1);
for (int j = 1; j <= m; ++j)
if (g[i][j] == 'J')
g[i][j] = '.', sx = i, sy = j;
}
fire();
int res = BFS();
if (~res)
cout << res << endl;
else
cout << "IMPOSSIBLE" << endl;
}
return 0;
}