UVA 11624-Fire!【双BFS】
<题目链接>
题目大意:
你的任务是帮助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】的更多相关文章
- UVA 11624 - Fire! 图BFS
看题传送门 昨天晚上UVA上不去今天晚上才上得去,这是在维护么? 然后去看了JAVA,感觉还不错昂~ 晚上上去UVA后经常连接失败作死啊. 第一次做图的题~ 基本是照着抄的T T 不过搞懂了图的BFS ...
- UVa 11624 Fire!(BFS)
Fire! Time Limit: 5000MS Memory Limit: 262144KB 64bit IO Format: %lld & %llu Description Joe ...
- (简单) UVA 11624 Fire! ,BFS。
Description Joe works in a maze. Unfortunately, portions of the maze have caught on fire, and the ow ...
- UVA - 11624 Fire! 【BFS】
题意 有一个人 有一些火 人 在每一秒 可以向 上下左右的空地走 火每秒 也会向 上下左右的空地 蔓延 求 人能不能跑出来 如果能 求最小时间 思路 有一个 坑点 火是 可能有 多处 的 样例中 只有 ...
- UVA - 11624 Fire! 双向BFS追击问题
Fire! Joe works in a maze. Unfortunately, portions of the maze have caught on fire, and the owner of ...
- uva 11624 Fire! 【 BFS 】
按白书上说的,先用一次bfs,求出每个点起火的时间 再bfs一次求出是否能够走出迷宫 #include<cstdio> #include<cstring> #include&l ...
- BFS(两点搜索) UVA 11624 Fire!
题目传送门 /* BFS:首先对火搜索,求出火蔓延到某点的时间,再对J搜索,如果走到的地方火已经烧到了就不入队,直到走出边界. */ /******************************** ...
- UVa 11624 Fire!(着火了!)
UVa 11624 - Fire!(着火了!) Time limit: 1.000 seconds Description - 题目描述 Joe works in a maze. Unfortunat ...
- UVA - 11624 Fire! bfs 地图与人一步一步先后搜/搜一次打表好了再搜一次
UVA - 11624 题意:joe在一个迷宫里,迷宫的一些部分着火了,火势会向周围四个方向蔓延,joe可以向四个方向移动.火与人的速度都是1格/1秒,问j能否逃出迷宫,若能输出最小时间. 题解:先考 ...
- UVA 11624 Fire!【两点BFS】
Joe works in a maze. Unfortunately, portions of the maze have caught on fire, and the owner of the m ...
随机推荐
- POJ3694 Network【连通分量+LCA】
题意: 一个无向图可以有重边,下面q个操作,每次在两个点间连接一条有向边,每次连接后整个无向图还剩下多少桥(注意是要考虑之前连了的边,每次回答是在上一次的基础之上). 思路: 首先运行一次Tarjan ...
- 第19月第2天 cellForItemAtIndexPath 返回空
1. 动画需要获取当前的 Cell ,下面的调用在 viewDidLoad 中,有时候返回 nil,有时候成功. UICollectionView *cell = (UICollectionView* ...
- IO流总结笔记三
字节流: 抽象基类:InputStream, OutputStream. 字节流可以操作任何数据.注意:字符流使用的数组是字符数组.Char [] chs 字节流使用的数组是字节数组.Byte [ ...
- ubuntu16.10安装docker17.03.0-ce并配置国内源和加速器
说明:这个针对docker-ce安装,ce和ee的区别是前者是社区版,后者是企业版 1. 配置Ubuntu的源,不然慢的去哭吧.参考http://cn.archive.ubuntu.com/help ...
- Java导出List集合到txt文件中——(四)
有时候,需要将数据以一定格式导出到txt文件中.利用Java的IO可以轻松的导出数据到txt中. package Action.txt; import java.io.BufferedWriter; ...
- pl/sql Devloper 如何查看表结构
在命令行 敲 desc 表名:
- ROS学习笔记(一) # ROS参数服务器
参考 roscpp/Overview/Parameter Server 0. 概述 ROS参数服务器能够保存 string, int, float, double, bool, list, dicti ...
- script & scriptreplay
script是什么 scirpt就是一个命令,可以制作一份记录输出到终端的记录.对于那些想要真实记录终端会话的人来说,这很有用.该记录可以保存并在以后再打印出来. 怎么用 默认情况下,我们可以通过在终 ...
- Sql 插入自定义主键
在遇到数据库设计是自增的主键,且需要插入自定义的主键Id时,这个时候如果直接Insert的话,将会发生错误,错误提示信息: 当 IDENTITY_INSERT 设置为 OFF 时,不能为表 'XXX' ...
- 【实践】Yalmip使用Knitro的一些总结
Yalmip使用Knitro的一些总结 1.软件 Knitro 11.0.1 Win64(包含安装包和确定机器ID的软件):链接:https://pan.baidu.com/s/14IfxlAdo3m ...