【暴力BFS】中山纪念中学暑期游Day10——洪水

前言

暴力BFS打丑了...100分完美变身20分...

题目

一天, 一个画家在森林里写生,突然爆发了山洪,他需要尽快返回住所中,那里是安
全的。
森林的地图由R行C列组成,空白区域用点“.”表示,洪水的区域用“*”表示,而
岩石用“X”表示,另画家的住所用“D”表示,画家用“S”表示。
有以下几点需要说明:
1、 每一分钟画家能向四个方向移动一格(上、下、左、右)
2、 每一分钟洪水能蔓延到四个方向的相邻格子(空白区域)
3、 洪水和画家都不能通过岩石区域
4、 画家不能通过洪水区域(同时也不行,即画家不能移到某个格子,该格子在画家达到的同时被洪水蔓延到了,这也是不允许的)
5、 洪水蔓不到画家的住所。
给你森林的地图,编写程序输出最少需要花费多长时间才能从开始的位置赶回家中。

Input

输入第一行包含两个整数R和C(R,C<=50)。
接下来R行每行包含C个字符(“.”、“*”、“X”、“D”或“S”)。地图保证只有一个“D”和一个“S”。

Output

输出画家最快安全到达住所所需的时间,如果画家不可能安全回家则输出“KAKTUS”。

Sample Input

输入1:
3 3 
D.* 
... 
.S. 

输入2:
3 3 
D.* 
...
..S

输入3:
3 6 
D...*. 
.X.X.. 
....S. 

Sample Output

输出1:
3

输出2:
KAKTUS 

输出3:
6

分析

本来是正解,我料到了“有多个洪水源点”的情况,结果没想到数据中有很多“没有洪水”的情况....开心20分爆掉...

法一:两次暴力BFS,

第一次BFS洪水到达(i,j)的最早时间,BFS的时候先把每一层的节点扩展完,然后时间t++,再把扩展出的新点一起压进队列

第二次BFS画家到达(i,j)的最早时间

法二:也是两次暴力BFS,用数组记录到达的时间(直接比上一次+1,就不用扩展完再压队那么复杂了)

要点注意:

1.洪水的源点可能有不止一个

2.要考虑图中没有洪水的情况

法一代码

#include<cstdio>
#include<queue>
#include<vector>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=50,INF=0x3f3f3f3f;
char a[MAXN+5][MAXN+5];
int dir1[5]={-1,0,1,0},dir2[5]={0,1,0,-1};
int f[MAXN+5][MAXN+5];//洪水到达(i,j)的最早时间 
bool vis[MAXN+5][MAXN+5];
int n,m,ans=0x3f3f3f3f;
int sx,sy,tx,ty;
bool flag=false;
struct node
{
	int x,y;
};
vector<node> water;
void bfs1()
{
	//tmp用来暂存扩展出的新一层的点 
	queue<node> que,tmp;
	int t=1;//开始时间定为1 
	node q,Tmp;
	for(int i=0;i<water.size();i++)
	{
		f[water[i].x][water[i].y]=t;
		que.push(water[i]);
	}
	while(!que.empty())
	{
		t++;
		while(!que.empty())//每次扩展完一整层
		{
			q=que.front();
			que.pop();
			for(int i=0;i<4;i++)
			{
				int dx=q.x+dir1[i],dy=q.y+dir2[i];
				if(f[dx][dy]==INF&&(a[dx][dy]=='.'||a[dx][dy]=='S'))
				{
					f[dx][dy]=t;
					Tmp.x=dx,Tmp.y=dy;
					tmp.push(Tmp);
				}
			}
		} 
		while(!tmp.empty())
		{
			que.push(tmp.front());
			tmp.pop();
		}
	}
}
void bfs2()
{
	queue<node> que,tmp;
	int t=1;//开始时间定为1 
	node q,Tmp;
	q.x=sx,q.y=sy;
	que.push(q);
	while(!que.empty())
	{
		t++;
		while(!que.empty())
		{
			q=que.front();
			que.pop();
			for(int i=0;i<4;i++)
			{
				int dx=q.x+dir1[i],dy=q.y+dir2[i];
				//printf("x:%d y:%d t:%d\n",dx,dy,t);
				if(a[dx][dy]=='.'&&t<f[dx][dy]&&!vis[dx][dy])
				{
					vis[dx][dy]=1;
					Tmp.x=dx,Tmp.y=dy;
					tmp.push(Tmp);
				}
				if(a[dx][dy]=='D')
				{
					flag=true;
					ans=min(ans,t);
				}
			}
		}
		while(!tmp.empty())
		{
			que.push(tmp.front());
			tmp.pop();
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",a[i]+1);
		for(int j=1;j<=m;j++)
		{
			if(a[i][j]=='S')
				sx=i,sy=j;
			if(a[i][j]=='D')
				tx=i,ty=j;
			if(a[i][j]=='*')//好像没说洪水起点只有一个... 
			{
				node tmp;
				tmp.x=i,tmp.y=j;
				water.push_back(tmp);
			}
		}
	}
	memset(f,INF,sizeof(f));
	bfs1();
	bfs2();
	if(flag)
		printf("%d",ans-1);//开始时间定为1
	else
		printf("KAKTUS");
	return 0;
}

法二代码

#include<cstdio>
#include<queue>
#include<vector>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=50,INF=0x3f3f3f3f;
char a[MAXN+5][MAXN+5];
int dir1[5]={-1,0,1,0},dir2[5]={0,1,0,-1};
int f[MAXN+5][MAXN+5];//洪水到达(i,j)的最早时间 
int t[MAXN+5][MAXN+5];
int n,m,ans=0x3f3f3f3f;
int sx,sy,tx,ty;
bool flag=false;
struct node
{
	int x,y;
};
vector<node> water;
void bfs1()
{
	queue<node> que;
	node q,tmp;
	for(int i=0;i<water.size();i++)
	{
		f[water[i].x][water[i].y]=1;//开始时间定为1
		que.push(water[i]);
	}
	while(!que.empty())
	{
		q=que.front();
		que.pop();
		for(int i=0;i<4;i++)
		{
			int dx=q.x+dir1[i],dy=q.y+dir2[i];
			if(f[dx][dy]==INF&&(a[dx][dy]=='.'||a[dx][dy]=='S'))
			{
				f[dx][dy]=min(f[dx][dy],f[q.x][q.y]+1);
				tmp.x=dx,tmp.y=dy;
				que.push(tmp);
			}
		}
	} 
}
void bfs2()
{
	queue<node> que;
	t[sx][sy]=1;//开始时间定为1
	node q,tmp;
	q.x=sx,q.y=sy;
	que.push(q);
	while(!que.empty())
	{
		q=que.front();
		que.pop();
		for(int i=0;i<4;i++)
		{
			int dx=q.x+dir1[i],dy=q.y+dir2[i];
			if(a[dx][dy]=='D')
			{
				flag=true;
				ans=min(ans,t[q.x][q.y]+1);
			}
			if(a[dx][dy]=='.'&&t[q.x][q.y]+1<f[dx][dy]&&!t[dx][dy])
			{
				t[dx][dy]=t[q.x][q.y]+1;
				tmp.x=dx,tmp.y=dy;
				que.push(tmp);
			}
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",a[i]+1);
		for(int j=1;j<=m;j++)
		{
			if(a[i][j]=='S')
				sx=i,sy=j;
			if(a[i][j]=='D')
				tx=i,ty=j;
			if(a[i][j]=='*')//好像没说洪水起点只有一个... 
			{
				node tmp;
				tmp.x=i,tmp.y=j;
				water.push_back(tmp);
			}
		}
	}
	memset(f,INF,sizeof(f));
	if(water.size()>0)
		bfs1();
	bfs2();
	if(flag)
		printf("%d",ans-1);//开始时间定为1
	else
		printf("KAKTUS");
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值