题目描述:
小明最后也没能进入游戏大厂,也没能娶到心爱的女孩,现在小明在一家迷宫里工作。 不幸的是,迷宫里因为线路老化而发生了火灾。小明现在需要一个逃跑路线,请你帮助倒霉的小明从迷宫中逃离出去吧 小明在迷宫中编号为 J 的位置,根据小明在迷宫中的位置以及迷宫中着火的位置(F),你必须确定在火焰烧到小明之前,他是否能逃离迷宫,如果能,他能多快逃离。 小明每分钟移动一个方格(上、下、左、右四个方向中的一个),但是火焰一分钟能向四个方向同时蔓延。小明可以从迷宫的任何一个边界逃离。无论是小明还是火都不会到达有墙的位置。
//找个工作被火追着跑,找个女朋友追着人家跑,典型的舔狗+宅男hh
输入:
输入的第一行包含一个整数,即测试数 每个测试用例的第一行包含两个整数R和C,用空格分隔,1≤ R、 C≤ 1000 以下R行中的每一行都包含C个字符,每个字符都是以下字符之一: #,一堵墙 .,空地,小明和火都可以通过 J,小明在迷宫中的初始位置 F,着火的广场(可能不止一处) 每个测试用例中只有一个J。
输出:
对于每个测试用例,如果小明不能在火烧到之前退出迷宫,则输出一行 “IMPOSSIBLE” 如果能逃出迷宫,则输出小明最快可以在几分钟内安全的逃出迷宫,每组输出占一行
2 | 3 |
4 4 | IMPOSSIBLE |
#### | |
#JF# | |
#..# | |
#..# | |
3 3 | |
### | |
#J. | |
#.F |
思路:
最短路---bfs,但是这个题的元素除了人还多了火,且这个火是朝四周蔓延的,一开始想到确实是用两个数组分别存住火和人所能到达的地点,在判断。但是出于种种顾虑,还是取消了这一做法。事实上,就是这么做。。。
正解:用两个bfs分别遍历火和人,注意!火碰到石头不能走,否则下次火就可能蔓延到石头的四周,造成错误,一定要特判;
本题最妙的地方就是用time数组来记录一下人到达当前地点的时候,火烧没烧过来,实际就是记录火与人烧到当前这个点需要几秒,当time.people<time.fire,才能继续bfs的。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int N=1005;
const int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//方向数组
struct Node//队列中多组数据
{
int x,y,t;
Node(){};
Node(int x,int y,int t):x(x),y(y),t(t){};
};
int a[N][N],vis[N][N],Time[N][N];//Time[x][y]是火蔓延到当前点所需的时间
inline int read()//正常快读
{
char ch=getchar();
while(ch!='#'&&ch!='J'&&ch!='F'&&ch!='.')
{
ch=getchar();
}
if(ch=='#') return 1;//将字符转化成字母,简化后面代码难度
else if(ch=='.') return 0;
else if(ch=='J') return -1;
else return -2;
}
void solve()
{
memset(a,0,sizeof(a));
memset(vis,0,sizeof(vis));
memset(Time,0,sizeof(Time));
int n,m;
cin>>n>>m;
Node s,f;//s是人,f是火
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int t=read();//读入数据
if(t==-1)//将起点和终点当做正常的点看,提前压入队列
{
s=Node(i,j,1);
t=0;
}
else if(t==-2)
{
f=Node(i,j,1);
t=0;
}
a[i][j]=t;
}
}
queue<Node> q;
q.push(f);
Time[f.x][f.y]=1;
//Time[x][y]是火蔓延到当前点所需的时间
for(;!q.empty();q.pop())
{
int x=q.front().x,y=q.front().y,t=q.front().t;
for(int i=0;i<4;i++)
{
int xx=x+dir[i][0];
int yy=y+dir[i][1];
if(xx<0&&yy<0||xx>n+1||yy>n+1||a[xx][yy]!=0||Time[xx][yy]>0)
{
continue;
}
q.push(Node(xx,yy,t+1));
Time[xx][yy]=t+1;
}
}
q.push(s);
vis[s.x][s.y]=1;
bool flag=false;
for(;!q.empty();q.pop())
{
int x=q.front().x,y=q.front().y,t=q.front().t;
if(x==0||x==n+1||y==0|y==n+1)
{
cout<<t-1<<endl;
flag=true;
break;
}
for(int i=0;i<4;i++)
{
int xx=x+dir[i][0];
int yy=y+dir[i][1];
if(xx<0||yy<0||xx>n+1||yy>n+1||a[xx][yy]!=0||vis[xx][yy]||t+1>Time[xx][yy])
//人走到这比火走到这时间短
{
continue;
}
q.push(Node(xx,yy,t+1));
vis[xx][yy]=1;
}
}
if(!flag) cout<<"IMPOSSIBLE"<<endl;
}
int main()
{
int T;
cin>>T;
while(T--)
{
solve(); //不在main函数里写能整洁明了
}
return 0;
}
总结:难点就是用两个bfs分别遍历和time数组的使用,剩下的均是普通bfs,两个bfs分别遍历不难想,处理好细节就Aceepted,即AC啦!
创作不易,请勿白嫖!麻烦给作者一个三连+关注,谢!