<题目链接>

题目大意:

你的任务是帮助J走出一个大火蔓延的迷宫。J每分钟可以超上下左右四个方向移动,而所有着火的格子每一分钟都会往四个方向蔓延一格。迷宫中有一些障碍,J和火都无法进入。当J走出迷宫的边界时,逃离成功。

解题分析:

注意,刚开始不一定只有一个格子着火。看到这道题,很容易想到要用BFS,火的蔓延和人的行走都用BFS模拟一下。先将火蔓延到所有点的最短时间通过bfs模拟求出来,然后再对人行走的过程用bfs进行模拟,从而计算出该人到达每个点的最短时间,如果人到达该点的最短时间晚于火到达的最短时间,那么该点不能走。根据这些,判断该人是否能够达到边界,即逃出迷宫。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm> using namespace std; const int MAXN = ;
const int INF = 0x3f3f3f3f;
const int dx[] = {-, , , };
const int dy[] = {, -, , }; struct node{
node (int xx, int yy, int dd) {
x = xx;
y = yy;
d = dd;
}
int x, y, d;
}; char g[MAXN][MAXN];
int vf[MAXN][MAXN], vm[MAXN][MAXN];
int T[MAXN][MAXN]; //记录火蔓延到的点的最短时间,以便判断人是否是在火烧到该点之前就能够到达该点
int r, c, sx, sy; queue<node> qf; void bfs_fire() { //bfs模拟火的蔓延过程
while (!qf.empty()) {
node u = qf.front();
qf.pop();
node v = u;
for (int i = ; i < ; i++){
int tx = u.x + dx[i];
int ty = u.y + dy[i];
if (tx < || tx >= r || ty < || ty >= c || g[tx][ty] == '#') continue;
if (!vf[tx][ty]) {
vf[tx][ty] = ;
T[tx][ty] = u.d+; //记录火蔓延到的点的最短时间,以便判断人是否是在火烧到该点之前就能够到达该点
qf.push(node(tx,ty,u.d+));
}
}
}
} int bfs_man() {
queue<node> qm;
while (!qm.empty()) qm.pop();
node s(sx, sy, );
qm.push(s);
memset(vm, , sizeof(vm));
vm[sx][sy] = ;
while (!qm.empty()) {
node u = qm.front();
qm.pop();
if (u.x == || u.x == r - || u.y == || u.y == c - ) //达到边界
return u.d + ;
node v = u;
for (int i = ; i < ; i++) {
int tx = u.x + dx[i];
int ty = u.y + dy[i];
if (tx < || tx >= r || ty < || ty >= c || g[tx][ty] == '#') continue;
if (u.d + >= T[tx][ty]) continue; //如果在这个人来之前,火就烧到了这里,则这个点不能走,这里很关键
if (!vm[tx][ty]){ //如果这个点能走且该人之前没走过
vm[tx][ty] = ;
qm.push(node(tx,ty,u.d+));
}
}
}
return -;
} int main() {
int cas;
scanf("%d", &cas);
while (cas--) {
scanf("%d%d", &r, &c);
for (int i = ; i < r; i++)
scanf("%s", g[i]); while(!qf.empty()) qf.pop();
memset(vf, , sizeof(vf));
memset(T, INF, sizeof(T)); for (int i = ; i < r; i++) {
for (int j = ; j < c; j++) {
if (g[i][j] == 'J') {
sx = i;
sy = j;
}
if (g[i][j] == 'F') { //注意,着火点不止有一个
node tmp(i, j, );
vf[i][j] = ;
T[i][j] = ;
qf.push(tmp);
}
}
} bfs_fire(); //先提前计算,火能够蔓延到的点的最短时间
int ans = bfs_man();
if (ans == -)
printf("IMPOSSIBLE\n");
else
printf("%d\n", ans);
}
return ;
}

下面还有一种想法:

通过模拟,火先蔓延一步,人再走一步,因为只有最新蔓延的火,才会对下一步的蔓延到其他点做出贡献,所以,每次只记录新蔓延出来的点,如下面的que[]数组模拟队列,用head和topend来控制只对新蔓延的点进行烧火模拟,达到“火蔓延一步”,“人走一步”的效果。但是下面的这段代WA了,不知道是不是我的思路有问题,先记录着。

#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std; const int maxn=+; int n,m,flag,ans;
char mpa[maxn][maxn];
int vis[maxn][maxn];
int head,topend; int dir[][]={,,,,-,,,-}; struct node{
int x,y;
int step;
node(int a=,int b=,int c=){
x=a,y=b,step=c;
}
}st,et,que[maxn*maxn]; void fire(){ //每次只更新一步
int top=topend;
while(head<top){ //上一次刚蔓延到的所有点,用小于是因为每次蔓延到新的点都是topend++
node now=que[head];
head++;
for(int k=;k<;k++){
int xx=now.x+dir[k][];
int yy=now.y+dir[k][]; //超界或者已经蔓延过的点,就不用再蔓延了
if(xx<||xx>n||yy<||yy>m||mpa[xx][yy]!='.')continue;
mpa[xx][yy]='*';
que[topend++]=node(xx,yy,now.step); //火烧的过程不算在走的步数中
}
}
} void bfs(){
memset(vis,,sizeof(vis));
queue<node>q;
vis[st.x][st.y]=;
q.push(st);
while(!q.empty()){
node now=q.front();
q.pop();
if(now.x==||now.x==n||now.y==||now.y==m){
flag=;
ans=now.step;
return;
}
fire(); //模拟烧火过程
for(int k=;k<;k++){
int xx=now.x+dir[k][];
int yy=now.y+dir[k][];
if(xx<||xx>n||yy<||yy>m||vis[xx][yy]||mpa[xx][yy]!='.')continue;
vis[xx][yy]=;
q.push(node(xx,yy,now.step+));
}
}
} int main(){
int t;scanf("%d",&t);
while(t--){
scanf("%d %d",&n,&m);
memset(mpa,,sizeof(mpa));
memset(que,,sizeof(que));
head=topend=;
for(int i=;i<=n;i++){
scanf("%s",mpa[i]+);
for(int j=;j<=m;j++){
if(mpa[i][j]=='J'){
st=node(i,j,);
mpa[i][j]='.';
}
if(mpa[i][j]=='F'){
et=node(i,j,);
que[topend++]=et; //着火点不止有一个
mpa[i][j]='*';
}
}
}
flag=;
bfs();
if(flag){
printf("%d\n",ans+);
}
else printf("IMPOSSIBLE\n");
}
return ;
}

2018-08-29

UVA 11624-Fire!【双BFS】的更多相关文章

  1. UVA 11624 - Fire! 图BFS

    看题传送门 昨天晚上UVA上不去今天晚上才上得去,这是在维护么? 然后去看了JAVA,感觉还不错昂~ 晚上上去UVA后经常连接失败作死啊. 第一次做图的题~ 基本是照着抄的T T 不过搞懂了图的BFS ...

  2. UVa 11624 Fire!(BFS)

    Fire! Time Limit: 5000MS   Memory Limit: 262144KB   64bit IO Format: %lld & %llu Description Joe ...

  3. (简单) UVA 11624 Fire! ,BFS。

    Description Joe works in a maze. Unfortunately, portions of the maze have caught on fire, and the ow ...

  4. UVA - 11624 Fire! 【BFS】

    题意 有一个人 有一些火 人 在每一秒 可以向 上下左右的空地走 火每秒 也会向 上下左右的空地 蔓延 求 人能不能跑出来 如果能 求最小时间 思路 有一个 坑点 火是 可能有 多处 的 样例中 只有 ...

  5. UVA - 11624 Fire! 双向BFS追击问题

    Fire! Joe works in a maze. Unfortunately, portions of the maze have caught on fire, and the owner of ...

  6. uva 11624 Fire! 【 BFS 】

    按白书上说的,先用一次bfs,求出每个点起火的时间 再bfs一次求出是否能够走出迷宫 #include<cstdio> #include<cstring> #include&l ...

  7. BFS(两点搜索) UVA 11624 Fire!

    题目传送门 /* BFS:首先对火搜索,求出火蔓延到某点的时间,再对J搜索,如果走到的地方火已经烧到了就不入队,直到走出边界. */ /******************************** ...

  8. UVa 11624 Fire!(着火了!)

    UVa 11624 - Fire!(着火了!) Time limit: 1.000 seconds Description - 题目描述 Joe works in a maze. Unfortunat ...

  9. UVA - 11624 Fire! bfs 地图与人一步一步先后搜/搜一次打表好了再搜一次

    UVA - 11624 题意:joe在一个迷宫里,迷宫的一些部分着火了,火势会向周围四个方向蔓延,joe可以向四个方向移动.火与人的速度都是1格/1秒,问j能否逃出迷宫,若能输出最小时间. 题解:先考 ...

  10. UVA 11624 Fire!【两点BFS】

    Joe works in a maze. Unfortunately, portions of the maze have caught on fire, and the owner of the m ...

随机推荐

  1. vue pc端网站项目开发坑点与难度记录

    背景 在一pc端的web项目里,由于某些特性需要由动态语言处理,所以只在有需要使用vue来处理数据的页面,直接引入vue.js来处理.由于刚开始并没有打算使用前端来渲染数据和处理交互,所以使用了一些非 ...

  2. JavaScript学习 - 基础(六) - DOM基础操作

    DOM: DOM定义了访问HTML 和XML 文档的标准:1.核心DOM 针对结构化文档的标准模型2.XMK DOM 针对XML文档的标准模型3.HTML DOM 针对HTML文档的标准模型 DOM节 ...

  3. [转]python 装饰器

    以前你有没有这样一段经历:很久之前你写过一个函数,现在你突然有了个想法就是你想看看,以前那个函数在你数据集上的运行时间是多少,这时候你可以修改之前代码为它加上计时的功能,但是这样的话是不是还要大体读读 ...

  4. nginx 配置文件[转]

    #运行用户 user nobody; #启动进程,通常设置成和cpu的数量相等 worker_processes 1; #全局错误日志及PID文件 #error_log logs/error.log; ...

  5. 基于theano的降噪自动编码器(Denoising Autoencoders--DA)

    1.自动编码器 自动编码器首先通过下面的映射,把输入 $x\in[0,1]^{d}$映射到一个隐层 $y\in[0,1]^{d^{'}}$(编码器): $y=s(Wx+b)$ 其中 $s$ 是非线性的 ...

  6. RPC原理

    RPC同步调用流程:(异步另说) 1)服务消费方(Client)以本地的调用方式调用远程服务. 2)客户端代理(Client Stub)接收到调用后负责将方法.参数等组装成能够进行网络传输的消息体. ...

  7. 恶意代码分析实战-x86反汇编速成班

    x86反汇编速成 x86体系结构 3种硬件构成: 中央处理器:负责执行代码 内存(RAM):负责存储所有的数据和代码 输入/输出系统(I/O):为硬盘.键盘.显示器等设备提供接口 内存 一个程序的内存 ...

  8. 【Shell】获取当前路径

    bathpath=$(cd dirname $0 ; pwd)

  9. 递归与尾递归(C语言)【转】

    作者:archimedes 出处:http://www.cnblogs.com/archimedes/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原 ...

  10. crontab定时作业

    crontab用于在指定时间执行某项作业,如执行脚本或命令. 1.crontab -e      创建一个crontab文件,并添加作业(这个crontab的拥有者是创建者). 这里要注意:必须指定s ...