BFS广度优先搜索(8)--uva11624(类似于双BFS)(能力题)

本文介绍了如何使用双BFS策略解决UVA11624迷宫问题。在这个问题中,主角Joe需要在火势蔓延的迷宫中找到最短的逃生路径。火源会每分钟向四周蔓延,同时Joe每分钟可以移动到相邻的四个位置。由于火源和Joe的移动速度相同,可以通过两个队列分别模拟Joe和火的移动。文章还提到可以预先处理火源信息,优化解决方案。中秋佳节,作者在学校通过编程度过,以此分享知识与思考。
摘要由CSDN通过智能技术生成

 Fire!

Time Limit: 1000MS     Memory Limit: 0KB     64bit IO Format: %lld & %llu


              

              

                 J:代表Joe  F:代表着火点(可能有多个) #:墙(障碍格)

               这道题是帮助Joe走出一个大火蔓延的迷宫。Joe每分钟可以走到上下左右4个方向的相邻格之一,而所有着火的格子都会往四周蔓延(即如果某个空格与着火格有公共边,则下一分钟这个空格将着火)。迷宫中有一些障碍格,Joe和火都无法进入。求Joe走出这个迷宫的最短时间(分钟)。

         这个题算是基本的广搜题吧!我想下它跟我们见过的最最基本的广搜有什么区别?是不是就是多了几个火源,而火源的作用是什么,是不是就是在蔓延的时候把一些能走的点变成不能走了,既然火源的速度和人一样,利用两个队列,一个储存人的状态,一个储存火的状态,把着火的点用fire的二维数组标记,首先将数据给出的着火点在fire数组中标记,然后每过一分钟,人先走一步(不能走着火点与障碍点,记录下步数),然后所有的着火点往四周(上下左右)拓展(不能拓展障碍点),如果人能顺利走出矩阵,则输出步数,否则输出IMPOSSIBLE。代码如下:

#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
int R,C;
char map[1010][1010];
int vis[1010][1010];
int fire[1010][1010];
int d[4][2]={1,0,0,1,-1,0,0,-1};   //上下左右四个方向
struct node{
	int x,y;
	int time;
};      //人的状态
struct node1{
	int x,y;
};        //火的状态
queue<node1>f;     //储存火状态的队列
int Bfs(int x,int y){
	int i,j;
	memset(vis,0,sizeof(vis));
	vis[x][y]=1;
	queue<node>q;  //储存人状态的队列
	node s,e;
	node1 b,c;
	s.x=x;
	s.y=y;
	s.time=0;
	q.push(s);
	while(!q.empty()){
		int cnt=q.size();//每次更新一层(就是当前队列中的所有状态都更新,注意是当前,不能直
		                 //接用i<q.size(),因为正在往队列中添加新的状态,而新的状态是下一次再更新)
		for(i=0;i<cnt;i++){      //人的状态的更新
			s=q.front();
			q.pop();
			if(fire[s.x][s.y])continue;     //着火点不能走
			for(j=0;j<4;j++){
				int xx=s.x+d[j][0];
				int yy=s.y+d[j][1];
				if(xx<0||yy<0||xx>=R||yy>=C)  //逃出迷宫(矩阵),注意时间要加一
					return s.time+1;
				if(map[xx][yy]=='#')continue;   //障碍点不能走
				if(fire[xx][yy])continue;     //着火点不能走
				if(vis[xx][yy])continue;       //已走过的点不能走
				vis[xx][yy]=1;
				e.x=xx;
				e.y=yy;
				e.time=s.time+1;
				q.push(e);
			}
		}
		cnt=f.size();              //每次更新一层(与人的状态的更新相同)
		for(i=0;i<cnt;i++){       //火的状态的更新
			b=f.front();
			f.pop();
			for(j=0;j<4;j++){
				int xx=b.x+d[j][0];
				int yy=b.y+d[j][1];
				if(xx<0||yy<0||xx>=R||yy>=C)
					continue;                    //越界
				if(map[xx][yy]=='#')continue;    //障碍点
				if(fire[xx][yy])continue;      //已经是着火点
				fire[xx][yy]=1;
				c.x=xx;
				c.y=yy;
				f.push(c);
			}
		}
	}
	return -1;       //走不出迷宫(矩阵)
}
int main()
{
	int T,i,j,x,y;
	scanf("%d",&T);
	while(T--){
		scanf("%d %d",&R,&C);
		memset(fire,0,sizeof(fire));
		for(i=0;i<R;i++)
		{
			scanf("%s",map[i]);
		}
		while(!f.empty()){
			f.pop();
		}
		for(i=0;i<R;i++){
			for(j=0;j<C;j++){
				if(map[i][j]=='J'){       //Joe开始所在的地方
					x=i;
					y=j;
				}
				else if(map[i][j]=='F'){     //初始化所有着火点
					node1 a;
					a.x=i;
					a.y=j;
					fire[i][j]=1;
					f.push(a);
				}
			}
		}
		int ans=Bfs(x,y);
		if(ans==-1)printf("IMPOSSIBLE\n");
		else printf("%d\n",ans);
	}
	return 0;
}

          另:这个题目有很多方法,如果你想的话 还可以先处理火源,把每个点最早到达的火源的时间记录下来,用所有的火源把地图处理完了之后再跑广搜。
         今天是中秋节,没回家,在学校,准备把这开学几周欠下的东西都弄一下,虽未与家人团聚吃月饼,但仍有代码相伴不寂寞。(文采依旧微笑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值