天鹅会面(BFS)

天鹅会面

题目描述

两头白天鹅生活在一个部分湖面结了冰的湖泊中,湖面的形状为一个长方形,并且被分割成R行C列的小方格,某些方格中结了冰,这样的方格称之为冰格,其余的方格称之为水格。冬天过去了,湖面上的冰渐渐开始溶解了,每一天与水相邻的冰格就将消融而转化为水格。所谓两个方格相邻是指它们在水平或垂直方向有公共边,两个呈对角的方格是不相邻的,下图给出样例数据的演化过程。

 

白天鹅只能在水中沿水平或垂直方向游动,写一个程序判断多少天后两只白天鹅才能够相会。

【输入格式】

输入文件第一行包含两个用空格隔开的整数R和C,其中1 ≤ R, C ≤ 1500,接下来的R行每行包含C个字符,描述湖面的初始状态,‘·’表示水格,‘ X’表示冰格,‘ L’表示一只白天鹅。

【输出格式】

输出文件仅一行包含一个整数表示两只白天鹅等到相邻那一天所需的天数。

【输入样例】

8 17

...XXXXXX..XX.XXX

....XXXXXXXXX.XXX

...XXXXXXXXXXXX..

..XXXXX.LXXXXXX..

.XXXXXX..XXXXXX..

XXXXXXX...XXXX...

..XXXXX...XXX....

....XXXXX.XXXL...

【输出样例】

2

Hint

30%数据1 ≤ R《400.1 ≤ C《300 

100%其中1 ≤ R, C ≤ 1500


看题目就可以感觉到是广搜,不过需要一些剪枝和优化。一定要先读清题,天鹅走是不耗费时间的,也就是说,只要两只天鹅被水域联通,就可以立刻遇见对方,所以限制相遇时间的是冰的融化程度。刚开始思路偏了,想从两只天鹅同时搜。。。

正确的做法是预处理出来冰的融化时间,然后以一只天鹅为起点进行广搜,还有一种类似SPFA的优化,进队前判断是否已经在队列里,但是我的方法加了优化会错误更新答案,所以卡常低空掠过。。。

注意:天鹅不需要在同一点才能相遇,相邻就可以了。珍爱生命,远离STL!!!内存超限少不了,循环队列大法好。

代码如下

#include<cstdio>
#include<iostream>
#include<cstring>
#define maxn 1501
#define maxx 20695015
#define fastcall __attribute__((optimize("-O3")))
#define IL __inline__ __attribute__((always_inline))//我也是迫不得已 
using namespace std;
fastcall IL int read()
{   char c=getchar();int x=0,y=1;
	while(c<'0'||c>'9'){if(c=='-') y=-1;c=getchar();}
	while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	return x*y;
}
fastcall IL int m_max(int x,int y){return x>y?x:y;}
const int mod=20695013;//模运算太慢,卡时限 
int n,m,cnt=0,mp[maxn][maxn],tail,head,steps[maxn][maxn];
struct node{int x,y,step;}q[maxx],tt[3];
fastcall IL void bfs1()//预处理融化时间 
{	while(head<=tail)
	{	node u=q[head];++head;
		if(u.x<n&&mp[u.x+1][u.y]==-1) mp[u.x+1][u.y]=2,steps[u.x+1][u.y]=u.step+1,q[++tail]=(node){u.x+1,u.y,u.step+1};
		if(u.x>1&&mp[u.x-1][u.y]==-1) mp[u.x-1][u.y]=2,steps[u.x-1][u.y]=u.step+1,q[++tail]=(node){u.x-1,u.y,u.step+1};
		if(u.y>1&&mp[u.x][u.y-1]==-1) mp[u.x][u.y-1]=2,steps[u.x][u.y-1]=u.step+1,q[++tail]=(node){u.x,u.y-1,u.step+1};
		if(u.y<m&&mp[u.x][u.y+1]==-1) mp[u.x][u.y+1]=2,steps[u.x][u.y+1]=u.step+1,q[++tail]=(node){u.x,u.y+1,u.step+1};
	}
} 
fastcall IL void bfs()
{	head=0;tail=0;
	q[tail]=tt[1];++tail;//STL太慢,为了节约内存用了循环队列 
	while(head!=tail) 
	{	node u=q[head];head++;if(head==mod) head=0;//枚举单点就足够,不需要枚举一条直线上的点,因为会由点推出路径 
		int tmp1=m_max(u.step,steps[u.x+1][u.y]),tmp2=m_max(u.step,steps[u.x-1][u.y]),tmp3=m_max(u.step,steps[u.x][u.y+1]),tmp4=m_max(u.step,steps[u.x][u.y-1]);
		if(u.x<n&&mp[u.x+1][u.y]>tmp1)//像SPFA一样松弛 
		{	mp[u.x+1][u.y]=tmp1;
			q[tail]=(node){u.x+1,u.y,tmp1};++tail;
			if(tail==mod) tail=0;//if(!ok[u.x+1][u.y]) ok[u.x+1][u.y]=1,优化大概是这样的,但我的方法不行 
		}
		if(u.x>1&&mp[u.x-1][u.y]>tmp2)
		{	mp[u.x-1][u.y]=tmp2;
			q[tail]=(node){u.x-1,u.y,tmp2};++tail;
			if(tail==mod) tail=0;//if(!ok[u.x-1][u.y]) ok[u.x-1][u.y]=1,
		}
		if(u.y>1&&mp[u.x][u.y-1]>tmp4)
		{	mp[u.x][u.y-1]=tmp4;
			q[tail]=(node){u.x,u.y-1,tmp4};++tail;
			if(tail==mod) tail=0;//if(!ok[u.x][u.y-1]) ok[u.x][u.y-1]=1,
		}
		if(u.y<m&&mp[u.x][u.y+1]>tmp3)
		{	mp[u.x][u.y+1]=tmp3;
			q[tail]=(node){u.x,u.y+1,tmp3};++tail;
			if(tail==mod) tail=0;//if(!ok[u.x][u.y+1]) ok[u.x][u.y+1]=1,
		}
	}
}
int main()
{  	//freopen("swan.in","r",stdin);
	//freopen("swan.out","w",stdout);
	head=1;tail=0;char c;
	n=read();m=read();
	for(int i=1;i<=n;++i)
	{	for(int j=1;j<=m;++j)
		{	c=getchar();while(c!='.'&&c!='L'&&c!='X') c=getchar();
			if(c=='.') mp[i][j]=2,q[++tail]=(node){i,j,0};
			else if(c=='L'){q[++tail]=(node){i,j,0};mp[i][j]=2;++cnt;if(cnt==1) steps[i][j]=0;tt[cnt]=(node){i,j,0};}
			else mp[i][j]=-1;
		}
	}
	bfs1();
	memset(mp,0x7f,sizeof(mp));
	bfs();
	printf("%d",mp[tt[2].x][tt[2].y]);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值