您的位置:首页 > 其它

大火蔓延的迷宫,白书P307Uva11624(BFS求最短路)

2017-11-10 00:04 471 查看
本题是非常好的一道题目。在常规的最短路题目中,增加了时间的概念,并且设置了火焰且可燃烧扩展。虽然看起来复杂,其实火焰的燃烧扩展本身也是一个最短路问题,只不过有多个源点而已。但是根据BFS的特点,开始时只要把多个源点同时放进队列中,即可正常多源点同时BFS扩展即可。

// UVa11624 Fire!
// Rujia Liu
#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];

queue<Cell> Q;
void bfs(int kind) {
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);

// 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: