思路:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
using namespace std;
typedef pair<int, int> P;
int dx[4] = { 0, 0, 1, -1 }, dy[4] = { -1, 1, 0, 0 };
const int N = 850;
int n, m, vis[N][N];
char mp[N][N];
int xg, yg, xb, yb, tot;
P gh[2];
bool ck(int x, int y, int cnt) {
if (x < 1 || x > n || y < 1 || y > m || mp[x][y] == 'X')
return 0;
for (int i = 0; i <= 1; i++)
if (abs(x - gh[i].first) + abs(y - gh[i].second) <= 2 * cnt)
return 0;
return 1;
}
void bfs() {
memset(vis, 0, sizeof vis);
queue<P> B, G;
B.push({ xb, yb });
vis[xb][yb] = 1;
G.push({ xg, yg });
vis[xg][yg] = 2;
for (int k = 1; B.size() || G.size(); k++) {
for (int tim = 1; tim <= 3; tim++) //男孩走三步
for (int S = B.size(); S; S--) { //将上一轮留下的所有位置探索一遍
P u = B.front();
B.pop();
int x = u.first, y = u.second;
if (!ck(x, y, k))
continue; //这里要在新的一轮的开始做判断 ,因为幽灵会先扩张领域
for (int i = 0; i < 4; i++) {
int nx = x + dx[i], ny = y + dy[i];
if (ck(nx, ny, k) && vis[nx][ny] != 1) {
if (vis[nx][ny] == 2) { //找到了女孩
printf("%d\n", k);
return;
}
vis[nx][ny] = 1;
B.push({ nx, ny });
}
}
}
for (int tim = 1; tim <= 1; tim++) //女孩走一步
for (int S = G.size(); S; S--) { //将上一轮留下的所有位置探索一遍
P u = G.front();
G.pop();
int x = u.first, y = u.second;
if (!ck(x, y, k))
continue; //这里要在新的一轮的开始做判断 ,因为幽灵会先扩张领域
for (int i = 0; i < 4; i++) {
int nx = x + dx[i], ny = y + dy[i];
if (ck(nx, ny, k) && vis[nx][ny] != 2) {
if (vis[nx][ny] == 1) { //找到了男孩
printf("%d\n", k);
return;
}
vis[nx][ny] = 2;
G.push({ nx, ny });
}
}
}
}
puts("-1");
return;
}
int main() {
int t;
scanf("%d", &t);
int i = 1;
while (i <= t) {
tot = 0; //漏了,搞了一个上午 QAQ
scanf("%d%d", &n, &m);
getchar();
for (int i = 1; i <= n; i++) {
scanf("%s", mp[i] + 1);
for (int j = 1; j <= m; j++) {
if (mp[i][j] == 'G')
xg = i, yg = j;
if (mp[i][j] == 'M')
xb = i, yb = j;
if (mp[i][j] == 'Z')
gh[tot].first = i, gh[tot++].second = j;
}
}
bfs();
++i;
}
return 0;
}