I—Fire(多个bfs搜索)

Fire(多个bfs搜索)

题目


题意:Joe被困在迷宫中,可以从边界逃出,但迷宫中有火,火和Joe同时移动,问Joe能否逃出迷宫。


解题思路:

 该题看起来很困难,因为我们可能会想到两个bfs搜索同时进行,
 如果这样就不知道从何处理了。因为这相当于两条盲驴乱撞,很难求出结果。
 那么,我们是否可以先进行一个再进行另一个呢?

显然是可以的,因为我们关键是要让Joe逃出迷宫,如果我是预言家,我先前就知道了火到达迷宫中各个点的时间,那么火和Joe同时烧,Joe不就可以根据火等等种种因素来判断行径吗?
所以,我们可以设置一个二维数组存储每个点火烧到的时间,当然,对于无法烧到的点我们设置其时间为无穷大
int times[maxn][maxn];

那么,通过对火bfs搜索记录每个点火烧到的时间,再通过这个去判断Joe能不能被火烧到,即Joe走到某点的时间如果小于times[x][y]那么说明不会被烧到。OK,以此对Joe进行一趟bfs搜索。则易解。

PS:一定一定要清空队列,一定一定要初始化数组,还有最重要的一点:火种不只是只有一个,可能有多个火种,即我们要进行多源点bfs搜索。


AC代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<stack>
#include<queue>
#include<cstring>
#include<memory.h>
#include<map>
#include<iterator>
#include<list>
#include<set>
#include<functional>

using namespace std;

const int maxn=1002;    //迷宫的最大尺寸。
const int INF=0x3f3f3f3f;//表示无穷大
char maze[maxn][maxn];//迷宫
bool visited[maxn][maxn];
int go[4][2]={{1,0},{0,1},{-1,0},{0,-1}};//代表操作行为。
int t,r,c;//t组测试用例,迷宫大小为r*c;
typedef struct node{
	int x,y;//当前状态Joe的坐标
	int step;//走到当前状态所消耗的时间
}node;
int times[maxn][maxn];//火燃烧到该点所需要消耗的时间。
queue<node> q1;
node fire,temp;
bool check_fire(int x,int y){
	//判断该点能否烧
	if(x>=0&&y>=0&&x<r&&y<c&&maze[x][y]!='#')
		return true;
	else return false;
}
int bfs_fire(){
	//先对火进行bfs搜索,记录燃烧到没点所需的时间,以便Joe做出选择。
	while(!q1.empty()){
		fire=q1.front();
		q1.pop();
		for(int i=0;i<4;i++){
			temp.x=fire.x+go[i][0];
			temp.y=fire.y+go[i][1];
			if(check_fire(temp.x,temp.y)&&times[temp.x][temp.y]>times[fire.x][fire.y]+1){
					//times[temp.x][temp.y]>times[fire.x][fire.y]+1   这个是为了找到烧到该点的最短时间。
				temp.step=fire.step+1;//火燃烧到此状态的时间。
				times[temp.x][temp.y]=times[fire.x][fire.y]+1;
				//存储此状态。
				q1.push(temp);
			}
		}
	}
	return 0;
}
bool check_joe(node temp){
	//检查Joe此点是否可走。
	if(!visited[temp.x][temp.y]&&temp.x>=0&&temp.y>=0&&temp.x<r&&temp.y<c&&maze[temp.x][temp.y]!='#')
		return true;
	else return false;
}
int bfs_Joe(node joe){
	queue<node> q2;
	q2.push(joe);
	visited[joe.x][joe.y]=true;
	while(!q2.empty()){
		joe=q2.front();
		q2.pop();
		if(joe.x==0||joe.x==r-1||joe.y==0||joe.y==c-1){
			//判断此时Joe是否逃出迷宫,到了边界再走一步就可逃出来了,可别忘了哦
			cout<<joe.step+1<<endl;
			return 0;
		}
		for(int i=0;i<4;i++){
			temp.x=joe.x+go[i][0];
			temp.y=joe.y+go[i][1];
			if(check_joe(temp)&&joe.step+1<times[temp.x][temp.y]){
				visited[temp.x][temp.y]=true;
				temp.step=joe.step+1;
				q2.push(temp);
			}
		}
	}
	printf("IMPOSSIBLE\n");
	return 0;
}
int main(){
	node joe;
	while(scanf("%d",&t)!=EOF){
		while(t--){
			memset(times,INF,sizeof(times));//初始化,设一开始烧到每个点的时间都是无穷大,因为有的点是烧不到的。
			scanf("%d%d",&r,&c);
			for(int i=0;i<r;i++){
				scanf("%s",maze[i]);
				for(int j=0;j<c;j++){
					if(maze[i][j]=='J'){
						joe.x=i;joe.y=j;joe.step=0;
						//寻找Joe的位置
					}
					else if(maze[i][j]=='F'){
						fire.x=i;fire.y=j;
						times[i][j]=0;
						//将火种入队
						q1.push(fire);
					}
				}
			}
			bfs_fire();
			memset(visited,false,sizeof(visited));
			//重置辅助数组,供Joe判断。
			bfs_Joe(joe);
		}
	}
	return 0;
}

posted @   unique_pursuit  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
点击右上角即可分享
微信分享提示