题目解释&数据范围
给定一张NM的地图,地图中有1个男孩,1个女孩和2个鬼。
字符“.”表示道路,字符“X”表示墙,字符“M”表示男孩的位置,字符“G”表示女孩的位置,字符“Z”表示鬼的位置。
男孩每秒可以移动3个单位距离,女孩每秒可以移动1个单位距离,男孩和女孩只能朝上下左右四个方向移动。
每个鬼占据的区域每秒可以向四周扩张2个单位距离,并且无视墙的阻挡,也就是在第k秒后所有与鬼的曼哈顿距离不超过2k的位置都会被鬼占领。
注意: 每一秒鬼会先扩展,扩展完毕后男孩和女孩才可以移动。
求在不进入鬼的占领区的前提下,男孩和女孩能否会合,若能会合,求出最短会合时间。
输入格式
第一行包含整数T,表示共有T组测试用例。
每组测试用例第一行包含两个整数N和M,表示地图的尺寸。
接下来N行每行M个字符,用来描绘整张地图的状况。(注意:地图中一定有且仅有1个男孩,1个女孩和2个鬼
输出格式
每个测试用例输出一个整数S,表示最短会合时间。
如果无***合则输出-1。
每个结果占一行。
数据范围
1<n,m<800
思路:我们把鬼的行动直接用距离公式计算即可,一旦我这个点的距离和鬼的距离<2
step的话,这个点就不可以走.那么鬼的就处理了,然后我们开两个队列,一个存boy的可行解,另一个存girl的可行解,一旦这个地方不合法了,就不扩展了,假如合法就扩展,我们用st[x][y]的1和2分别表示男孩和女孩,一旦男孩可以走的地方出现女孩,或者女孩可以走的地方出现男孩就直接return step;
代码实现:

#include <bits/stdc++.h>
using namespace std;
#define f first
#define s second
typedef pair<int,int> pi;
const int N=805;
int n,m,step=0;
char an[N][N];
int st[N][N];
pi ghost[2];
bool ck(int x,int y)
{
    if(x<0||x>=n||y<0||y>=m||an[x][y]=='X') return false;
    for(int i=0;i<2;i++)
    {
        if(abs(ghost[i].f-x)+abs(ghost[i].s-y)<=step*2) return false;
    }
    return true;
} 

int bfs()
{
    memset(st,0,sizeof st);
    step=0;
    int dx[4]={-1,1,0,0};int dy[4]={0,0,1,-1};
    pi boy,girl;int g=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(an[i][j]=='M')      { boy={i,j}; }//男孩
            else if(an[i][j]=='G') { girl={i,j}; }//女孩
            else if(an[i][j]=='Z') { ghost[g++]={i,j}; }//鬼
        }
    }
    queue<pi>qb,qg;
    qb.push(boy);qg.push(girl);
    while(qb.size()||qg.size())
    {
        step++;
        for(int i=0;i<3;i++)
        {
            for(int j=0,len=qb.size();j<len;j++)
            {
                auto t=qb.front();
                qb.pop();
                if(!ck(t.f,t.s)) continue;
                for(int k=0;k<4;k++)
                {
                    if(ck(t.f+dx[k],t.s+dy[k]))
                    {
                        if(!st[t.f+dx[k]][t.s+dy[k]])
                        {
                            st[t.f+dx[k]][t.s+dy[k]]=1;
                            qb.push({t.f+dx[k],t.s+dy[k]});
                        }
                        else if(st[t.f+dx[k]][t.s+dy[k]]==2)  return step;//假如这个点属于girl.拿出来的点boy肯定染色了的
                    }
                }
            }
        }//扩展3次
        for(int i=0,len=qg.size();i<len;i++)
        {
            auto t=qg.front();
            qg.pop();
            if(!ck(t.f,t.s)) continue;
            for(int k=0;k<4;k++)
            {
                if(ck(t.f+dx[k],t.s+dy[k]))
                {
                    if(!st[t.f+dx[k]][t.s+dy[k]])
                    {
                      st[t.f+dx[k]][t.s+dy[k]]=2;
                      qg.push({t.f+dx[k],t.s+dy[k]});
                    }
                    else if(st[t.f+dx[k]][t.s+dy[k]]==1)  return step;//假如这个点属于boy.拿出来的点girl肯定染色了的
                }
            }
        }
    }
    return -1;
}

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n>>m;
        for(int i=0;i<n;i++) cin>>an[i];
        cout<<bfs()<<endl;
    }
    return 0;
}