C/C++噩梦

3 篇文章 0 订阅

噩梦

题意:

给定一张 N×M 的地图,地图中有 1 个男孩,1 个女孩和 2 个鬼。
字符 . 表示道路,字符 X 表示墙,字符 M 表示男孩的位置,字符 G 表示女孩的位置,字符 Z 表示鬼的位置。
男孩每秒可以移动 3 个单位距离,女孩每秒可以移动 1 个单位距离,男孩和女孩只能朝上下左右四个方向移动。
每个鬼占据的区域每秒可以向四周扩张 2 个单位距离,并且无视墙的阻挡,也就是在第 k 秒后所有与鬼的曼哈顿距离不超过 2k 的位置都会被鬼占领。
注意: 每一秒鬼会先扩展,扩展完毕后男孩和女孩才可以移动。
求在不进入鬼的占领区的前提下,男孩和女孩能否会合,若能会合,求出最短会合时间。

code:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define ll long long
#define PLL pair<ll,ll>

using namespace std;
const int dx[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
ll t,n,m;
short js[810][810];
char c[810][810];
PLL b,g,ghost[2];
bool check(ll,ll,ll);
ll bfs();
int main()
{
	ios::sync_with_stdio(false);
	cin >> t;
	while(t--)
	{
		cin >> n >> m;
		ll cnt = 0;
		memset(js,0,sizeof(js));
		for(int i = 1;i <= n;++i)
		{
			for(int j = 1;j <= m;++j)
			{
				cin >> c[i][j];
				if(c[i][j] == 'M') b = make_pair(i,j);
				else if(c[i][j] == 'G') g = make_pair(i,j);
				else if(c[i][j] == 'Z') ghost[cnt++] = make_pair(i,j);
			}
		}
		cout << bfs() << endl;
		//cout << b.first << " " << b.second << endl;
		//cout << g.first << " " << g.second << endl;
		//cout << ghost[0].first << " " << ghost[0].second << endl;
		//cout << ghost[1].first << " " << ghost[1].second << endl;
	}
	return 0;
}

ll bfs()
{
	queue<PLL> qb,qg;
	qb.push(b);
	qg.push(g);
	
	ll dis = 0;
	while(qb.size()||qg.size())
	{
		PLL t;
		++dis;
		for(int i = 0;i < 3;++i)//走三次 
		{
			for(int j = 0,len = qb.size(),xx,yy;j < len;++j)
			{
				t = qb.front();
				qb.pop();
				
				xx = t.first;
				yy = t.second;
				if(!check(xx,yy,dis)) continue;
				for(int k = 0,x,y;k < 4;++k)
				{
					x = xx + dx[k][0];
					y = yy + dx[k][1];
					
					if(check(x,y,dis))
					{
						if(js[x][y] == 2)//GIRL
						{
							return dis;
						}
						if(!js[x][y])
						{
							js[x][y] = 1;//BOY
							qb.push(make_pair(x,y));
						}
					}
				}
			}
		}
		
		
		for(int j = 0,len = qg.size(),xx,yy;j < len;++j)
		{
			t = qg.front();
			qg.pop();
			
			xx = t.first;
			yy = t.second;
			if(!check(xx,yy,dis)) continue;//这一秒待着的地方是否被鬼占领 
			for(int k = 0,x,y;k < 4;++k)
			{
				x = xx + dx[k][0];
				y = yy + dx[k][1];
				
				if(check(x,y,dis))
				{
					if(js[x][y] == 1)//BOY
					{
						return dis;
					}
					if(!js[x][y])
					{
						js[x][y] = 2;//GIRL
						qg.push(make_pair(x,y));
					}
				}
			}
		}
	}
	return -1;
}

bool check(ll x,ll y,ll dis)
{
	if(x < 1||x > n||y < 1||y > m||c[x][y] == 'X') return false;
	for(int i = 0;i < 2;++i)
	{
		if(abs(x - ghost[i].first) + abs(y - ghost[i].second) <= (dis << 1)) return false;
	}
	return true;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值