题目大意
有n *m的棋盘,上面有‘M’,‘G’,‘Z’,‘.’,‘X’5种点,M(只有1个)每一次走0 ~ 3步均可,G(只有1个)每次走0 ~ 1步均可,都是4联通,不能进入X,Z有2个,在每个时刻i,可以占领曼哈顿距离<=2 *i的点,G和M同样不能进入占领区,每一时刻,由Z先占领,然后M,G开始移动,求M,G汇合的最短用时,如果不能汇合,输出-1,多组数据
思路
直接模拟G,M,Z的移动,但Z的移动只需判断G,M所到的点是否被占领,注意,一个在i时刻可以到达的点,如果在j(j>i)时刻被占领,不能对其扩展
code:
#include<iostream>
#include<queue>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m;
char a[810][810];
int q[4][2]={
{
0,1},{
1,0},{
-1,0},{
0,-1}},q2[2][2],tot;
queue< pair<int,int> > myd,dym,lyw;
pair<int,int> wj,kyx;
bool cmp(int x,int y,int z)
{
if (x<1||y<1||x>n||y>m||a[x][y]=='X') return 0;
for (int i=0;i<2;i++)
{
if (abs(x-q2[i][0])+abs(y-q2[i][1])<=2*z) return 0;
}
return 1;
}
inline int read()
{
int x=0,f=1;
char s=getchar();
while (s<'0'||s>'9')
{
if (s=='-') f=-f;
s=getchar();
}
while (s>='0'&&s<='9')
{
x=x*10+s-'0';
s=getchar();
}
return x*f;
}
int lhj=0;
pair<int,int> op;
bool xx(int z)
{
int s=myd.size();
while (s--)
{
for (int i=0;i<4;i++)
{
int dx=myd.front().first+q[i][0],dy=myd.front().second+q[i][1];
if (cmp(myd.front().first,myd.front().second,z)&&cmp(dx,dy,z)&&a[dx][dy]!='M')
{
if (a[dx][dy]=='G')
{
lhj=z;
return 1;
}
a[dx][dy]='M';
op.first=dx,op.second=dy;
myd.push(op);
}
}
myd.pop();
}
return 0;
}
bool yy(int z)
{
int s=dym.size();
while (s--)
{
for (int i=0;i<4;i++)
{
int dx=dym.front().first+q[i][0],dy=dym.front().second+q[i][1];
if (cmp(dym.front().first,dym.front().second,z)&&cmp(dx,dy,z)&&a[dx][dy]!='G')
{
if (a[dx][dy]=='M')
{
lhj=z;
return 1;
}
a[dx][dy]='G';
op.first=dx,op.second=dy;
dym.push(op);
}
}
dym.pop();
}
return 0;
}
int main()
{
int t=read(),i,j;
while (t--)
{
cin>>n>>m;
lhj=-1;
tot=0;
for (i=1;i<=n;i++) scanf("%s",a[i]+1);
for (i=1;i<=n;i++)
{
for (j=1;j<=m;j++)
{
if (a[i][j]=='Z')
{
q2[tot][0]=i;
q2[tot++][1]=j;
}
if (a[i][j]=='M')
{
wj.first=i,wj.second=j;
}
if (a[i][j]=='G')
{
kyx.first=i,kyx.second=j;
}
}
}
myd=lyw;
dym=lyw;
myd.push(wj),dym.push(kyx);
for (i=1;myd.size()||dym.size();i++)
{
if (xx(i)) break;
if (xx(i)) break;
if (xx(i)) break;
if (yy(i)) break;//论函数的妙用
}
cout<<lhj<<endl;
}
return 0;
}