UVA - 11624 - Fire!

题目描述:

小明最后也没能进入游戏大厂,也没能娶到心爱的女孩,现在小明在一家迷宫里工作。
不幸的是,迷宫里因为线路老化而发生了火灾。小明现在需要一个逃跑路线,请你帮助倒霉的小明从迷宫中逃离出去吧
小明在迷宫中编号为 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啦!
创作不易,请勿白嫖!麻烦给作者一个三连+关注,谢!

猜你喜欢

转载自blog.csdn.net/2301_76331300/article/details/131577195