(VUa 11624)Fire! -- BFS

题目连接:
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值