HDU 3085 Nightmare 双向bfs

20 篇文章 0 订阅

传送门:HDU3085

题意:

  n*m地图上有

  ‘. ’:路

  X:墙

  Z:鬼,每秒蔓延2个单位长度,可以穿墙,共两个,每秒开始时鬼先动 

  M:每分钟可移动3个单位长度

  G:每分钟课移动1个单位长度

问两人是否可在不被鬼吃掉的前提下成功碰面

思路:双向bfs,即对两人同时bfs,若某人走的格子另一个人已经走过,则说明能碰面,停止搜索。鬼到人的距离可以用曼哈顿距离计算,若小于 等于两倍的时间就说明人被吃掉了。

代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<vector>
#include<map>
#define ll long long
#define pi acos(-1)
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int>P;
int n,m;
char mp[808][808];
struct node{
	int r,c;
}G,M,z[2];
queue<node>q[2];
int time=0;
int go[4][2]={1,0,0,1,-1,0,0,-1};
bool book[2][808][808];
int bfs(int k)
{
	int cnt=q[k].size();
	while(cnt--)//把所有的情况都往前推进一步,切忌写成while(!q.empty()) 
	{
		node t=q[k].front(),a;
		q[k].pop();
		if(abs(t.r-z[0].r)+abs(t.c-z[0].c)<=time*2)continue;
		if(abs(t.r-z[1].r)+abs(t.c-z[1].c)<=time*2)continue;
		for(int i=0;i<4;i++)
		{
			a.r=t.r+go[i][0];
			a.c=t.c+go[i][1];
			if(a.c<0||a.r<0||a.r>=n||a.c>=m)continue;
			if(mp[a.r][a.c]=='X'||book[k][a.r][a.c])continue;
			if(abs(a.r-z[0].r)+abs(a.c-z[0].c)<=time*2)continue;
			if(abs(a.r-z[1].r)+abs(a.c-z[1].c)<=time*2)continue;
			if(book[k^1][a.r][a.c])return 1;
			book[k][a.r][a.c]=1;
			q[k].push(a);
		}
	}
	return 0;
}
int solve()
{
	memset(book,0,sizeof(book));
	while(!q[0].empty())q[0].pop();
	while(!q[1].empty())q[1].pop();
	q[0].push(M);
	q[1].push(G);
	book[0][M.r][M.c]=1;
	book[1][G.r][G.c]=1;
	while((!q[0].empty())||(!q[1].empty()))//只要有一个人能走就还有会面的希望 
	{
		time++;
		if(bfs(0))return time;
		if(bfs(0))return time;
		if(bfs(0))return time;
		if(bfs(1))return time;
	} 
	return -1;
}
int main()
{
	int	t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		int cnt=0;
		time=0;
		for(int i=0;i<n;i++)
		{
			scanf("%s",mp[i]);
			for(int j=0;j<m;j++)
			{
				if(mp[i][j]=='G')
				{
					G.r=i;
					G.c=j;
				}
				if(mp[i][j]=='M')
				{
					M.r=i;
					M.c=j;
				}
				if(mp[i][j]=='Z')
				{
					z[cnt].r=i;
					z[cnt++].c=j;
				}
			}
		}
		printf("%d\n",solve());
	 } 
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值