题意:传送门
题解:建立两个队列,每个时间下,每一轮中,先判下是否能走,之后男孩
b
f
s
bfs
bfs三层,女孩
b
f
s
bfs
bfs一层,记录可达性。中间位置的特判注意:每次先判鬼是否能到达,不是人先走。
#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
using namespace std;
const int N=8e2+5;
int T,n,m,st[N][N],cnt,dx[]={-1,1,0,0},dy[]={0,0,-1,1};
char g[N][N];
pii boy,girl,ghost[3];
bool check(int x,int y,int step)
{
if(x<0||x>=n||y<0||y>=m||g[x][y]=='X')return false;
for(int i=0;i<cnt;i++){
int t=abs(x-ghost[i].first)+abs(y-ghost[i].second);
if(t<=2*step)return false;
}
return true;
}
int bfs()
{
memset(st,0,sizeof(st));
cnt=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(g[i][j]=='M')boy={i,j};
else if(g[i][j]=='G')girl={i,j};
else if(g[i][j]=='Z')ghost[cnt++]={i,j};
}
}
queue<pii>qb,qg;
qb.push(boy);qg.push(girl);
st[boy.first][boy.second]=1;st[girl.first][girl.second]=2;
int step=0;
while(!qb.empty()||!qg.empty()){
step++;
for(int i=0;i<3;i++){
for(int i=0,j=qb.size();i<j;i++){
pii t=qb.front();
qb.pop();
int x=t.first,y=t.second;
if(!check(x,y,step))continue;
for(int k=0;k<4;k++){
int nx=x+dx[k],ny=y+dy[k];
if(!check(nx,ny,step))continue;
if(st[nx][ny]==2)return step;
if(st[nx][ny]==0){
st[nx][ny]=1;
qb.push({nx,ny});
}
}
}
}
for(int i=0,j=qg.size();i<j;i++){
pii t=qg.front();
qg.pop();
int x=t.first,y=t.second;
if(!check(x,y,step))continue;
for(int k=0;k<4;k++){
int nx=x+dx[k],ny=y+dy[k];
if(!check(nx,ny,step))continue;
if(st[nx][ny]==1)return step;
if(st[nx][ny]==0){
st[nx][ny]=2;
qg.push({nx,ny});
}
}
}
}
return -1;
}
int main()
{
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)scanf("%s",g[i]);
printf("%d\n",bfs());
}
return 0;
}