噩梦
题意:
给定一张 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;
}