题目连接:
http://acm.hust.edu.cn/vjudge/problem/28833
题意:
你的任务是帮助Joe走出一个大火蔓延的迷宫。joe每分钟可以走上下左右四个方向的相邻格子,而所有着火的格子每分钟都会向四周扩散。迷宫有些障碍joe和火到不能到达,我们认为当joe走到边界格子时就已经出了迷宫了。问最少的走出迷宫的时间,如果不能则输出:IMPOSSIBLE
分析:
如果没有火,那么这一题就是一个裸的bfs题。加上火之后怎么样呢?那也仅仅只是又加了一个到达每个格子的下界时间。我们只需要预处理每个格子的起火时间,搜索时加上一个判断即可。
如何求每个格子的起火时间?第一感觉就是以每个”F”bfs,取最小值。但是我们其实只需要开始时将所有“F”加入队列,进行一次bfs即可。(相当于加了一个“超级源”的思想。)
算法实现过程:
1:先搜索Joe到达每格的时间。
2:再搜索火到达每格的时间。
3:在四周边界找Joe到达时间< 火到达时间的最小时间。
AC代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int INF = 1000000000;
const int maxr = 1000 + 5;
const int maxc = 1000 + 5;
int R, C;
char maze[maxr][maxc];
struct Cell {
int r, c;
Cell(int r, int c):r(r),c(c) {}
};
const int dr[] = {-1,1,0,0};
const int dc[] = {0,0,-1,1};
int d[maxr][maxc][2], vis[maxr][maxc][2];//d[][][0],vis[][][0]:表示Joe到达每格的时间和是否到达,d[][][1],vis[][][1]:表示火到达每格时间和是否到达。
queue<Cell> Q;
void bfs(int kind) {//搜索Joe和火到达每格的时间
while(!Q.empty()) {
Cell cell = Q.front(); Q.pop();
int r = cell.r, c = cell.c;
for(int dir = 0; dir < 4; dir++) {
int nr = r + dr[dir], nc = c + dc[dir];
if(nr >= 0 && nr < R && nc >= 0 && nc < C && maze[nr][nc] == '.' && !vis[nr][nc][kind]) {
Q.push(Cell(nr, nc));
vis[nr][nc][kind] = 1;
d[nr][nc][kind] = d[r][c][kind] + 1;
}
}
}
}
int ans;
void check(int r, int c) {
if(maze[r][c] != '.' || !vis[r][c][0]) return; // 必须是Joe可达的边界格子
if(!vis[r][c][1] || d[r][c][0] < d[r][c][1]) ans = min(ans, d[r][c][0] + 1); // Joe必须先于火到达
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &R, &C);
int jr, jc;
vector<Cell> fires;
for(int i = 0; i < R; i++) {
scanf("%s", maze[i]);
for(int j = 0; j < C; j++)
if(maze[i][j] == 'J') { jr = i; jc = j; maze[i][j] = '.'; }
else if(maze[i][j] == 'F') { fires.push_back(Cell(i,j)); maze[i][j] = '.'; }
}
memset(vis, 0, sizeof(vis));
// Joe
vis[jr][jc][0] = 1; d[jr][jc][0] = 0;
Q.push(Cell(jr, jc));
bfs(0);//计算从J到每格的时间
// Fire
for(int i = 0; i < fires.size(); i++) {
vis[fires[i].r][fires[i].c][1] = 1;
d[fires[i].r][fires[i].c][1] = 0;
Q.push(fires[i]);
}
bfs(1);//计算火到每格的时间
// 计算答案
ans = INF;
for(int i = 0; i < R; i++) { check(i,0); check(i,C-1); }
for(int i = 0; i < C; i++) { check(0,i); check(R-1,i); }
if(ans == INF) printf("IMPOSSIBLE\n"); else printf("%d\n", ans);
}
return 0;
}