ACM简单搜索Fire!--BFS

ACM简单搜索Fire!–BFS

Joe works in a maze. Unfortunately, portions of the maze havecaught on re, and the owner of the maze neglected to create a reescape plan. Help Joe escape the maze.Given Joe’s location in the maze and which squares of the mazeare on re, you must determine whether Joe can exit the maze beforethe re reaches him, and how fast he can do it.Joe and the re each move one square per minute, vertically orhorizontally (not diagonally). The re spreads all four directionsfrom each square that is on re. Joe may exit the maze from anysquare that borders the edge of the maze. Neither Joe nor the remay enter a square that is occupied by a wall.

Input
The first line of input contains a single integer, the number of testcases to follow. The rst line of each test case contains the twointegersRandC, separated by spaces, with 1R;C1000. ThefollowingRlines of the test case each contain one row of the maze. Each of these lines contains exactlyCcharacters, and each of these characters is one of:
’#’, a wall.,
‘.’ a passable square
’j’, Joe’s initial position in the maze, which is a passable square
’F’, a square that is on fire
There will be exactly one J in each test case.

Output
For each test case, output a single line containing `IMPOSSIBLE’ if Joe cannot exit the maze before the re reaches him, or an integer giving the earliest time Joe can safely exit the maze, in minutes.

Sample Input

2
4 4
####
#JF#
#..#
#..#
3 3
###
#J.
#.F

Sample Output

3

IMPOSSIBLE

题目大意:农夫约翰的农场发生火灾,有多个地方起火了,J是约翰一开始出现的位置,F是火焰出现的位置(注意火焰有多个,样例只显示一个让很多人误以为只有一个火焰),#表示障碍物火焰和约翰都不能到达,. 表示约翰和火焰都可以到达的道路,约翰可以每分钟移动到上下左右的任意一个位置,不幸的是火焰也可以在每分钟同时向上下左右燃烧移动,约翰需要逃离农场(也就是问约翰能否在火焰燃烧的同时离开地图边界),火焰燃烧到的地方约翰是不能通过的,如果可以到达输出最小花费时间,如果不能输出“IMPOSSIBLE”。

解题思路:
我们首先想想在没有火焰的情况下,就是一道很基础的BFS搜索路径问题,但是有了火焰,我们就可以设想到达某个位置(x,y)是约翰先到达,还是火焰先到达,如果约翰先到达,就说明可以通过(先溜了再说),如果是火焰先到达,就说明不能通过。那么也变成了一个简单的BFS搜索问题,但是如何知道某个位置(x,y)是约翰还是火焰先到达呢,就可以定义一个tim[maxn][maxn]的表示火焰燃烧到某个位置花的时间,首先把所有火焰位置记录下来,然后装入队列里先进行一次BFS,遍历地图,然后用tim数组不断记录火焰到达某个位置(x,y)花的时间,然后再对约翰J进行最后的BFS遍历,如果此时到达某个点(x,y)约翰的时间J.tim>=tim[x][y]说明火焰已经比约翰先到达了,就不能通过,做个判断就行了,然后问题就解决了。

注意tim[maxn][maxn]数组的初始化要为正无穷,因为有些点火焰是一直没法到达的,时间上就为无穷。

AC代码

#include<iostream>
#include<queue>
#include<string.h>
#include<string>
using namespace std;
struct Node{
	int x,y,dp;
};
queue<Node>q;
char mp[1010][1010];
int tim[1010][1010];
bool vis[1010][1010];
int n,m;
int xx[4]={1,-1,0,0};
int yy[4]={0,0,1,-1};
int x,y;
//BFS1()先对火焰进行时间tim遍历
void BFS1()
{
	while(!q.empty())
	q.pop();
	memset(vis,0,sizeof(vis));
	Node t;
	//初始化时间正无穷
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
	{
		tim[i][j]=1e8;
		//针对某些点一开始就出现火焰,时间定义为0
		if(mp[i][j]=='F')
		{
			t.x=i,t.y=j,t.dp=0;
			tim[i][j]=0;
			vis[i][j]=true;
			q.push(t);
		}
		if(mp[i][j]=='J')
		x=i,y=j;
	}
	while(!q.empty())
	{
		t=q.front();
		q.pop();
		for(int i=0;i<4;i++)
		{
			Node w=t;
			w.x+=xx[i];
			w.y+=yy[i];
			w.dp++;
			if(w.x<1||w.x>n||w.y<1||w.y>m)continue;
			if(vis[w.x][w.y])continue;
			if(mp[w.x][w.y]=='#')continue;
			vis[w.x][w.y]=true;
			tim[w.x][w.y]=w.dp;
			q.push(w);
		}
	}
}
//开始约翰的遍历
void BFS2()
{
	while(!q.empty())
	q.pop();
	memset(vis,0,sizeof(vis));
	Node t;
	t.x=x,t.y=y,t.dp=0;
	vis[x][y]=true;
	q.push(t);
	while(!q.empty())
	{
		t=q.front();
		q.pop();
		for(int i=0;i<4;i++)
		{
			Node w=t;
			w.x+=xx[i];
			w.y+=yy[i];
			w.dp++;
			if(w.x<1||w.x>n||w.y<1||w.y>m)
			{
				cout<<w.dp<<endl;
				return;
			}
			if(vis[w.x][w.y])continue;
			//约翰的用时已经大于火焰,不能通过,返回
			if(w.dp>=tim[w.x][w.y])continue;
			if(mp[w.x][w.y]=='#')continue;
			vis[w.x][w.y]=true;
			q.push(w);
		}
	}
	cout<<"IMPOSSIBLE\n";
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		cin>>n>>m;
		for(int i=1;i<=n;i++)
		scanf("%s",mp[i]+1);
		BFS1();
		BFS2();
	}
}
/*
2
4 4
####
#JF#
#..#
#..#
3 3
###
#J.
#.F
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值