>Link
HDOJ3085
>解题思路
由于有鬼的限制,我们需要开两个队列,一个记录男孩一个记录女孩,两个bfs同时进行,如果女孩走到了男孩走到过的地方,说明两个相遇了,这时所用时间就是答案
注意男孩一次可以走三步,女孩走一步,所以一次bfs,男孩需要处理三层,女孩处理一层
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#define N 810
using namespace std;
const int xx[4] = {
-1, 0, 0, 1}, yy[5] = {
0, -1, 1, 0};
struct node
{
int x, y;
};
int T, n, m, z[5][5], cntz, vis[N][N], ans;
bool mark[N][N];
char cc;
queue<node> q1, q2;
int read ()
{
int l = 0; cc = getchar();
while (cc < '0' || cc > '9') cc = getchar();
while (cc >= '0' && cc <= '9') {
l = l * 10 + cc - '0'; cc = getchar();}
return l;
}
bool check (int x, int y, int w)
{
if (x < 1 || x > n || y < 1 || y > m) return 0;
if (mark[x][y]) return 0;
if (abs (x - z[1][0]) + abs (y - z[1][1]) <= 2 * w) return 0;
if (abs (x - z[2][0]) + abs (y - z[2][1]) <= 2 * w) return 0;
return 1;
}
void work ()
{
memset (vis, 0, sizeof (vis)); //记录男孩或女孩是否走过
memset (mark, 0, sizeof (mark)); //记录墙
cntz = ans = 0;
while (!q1.empty()) q1.pop();
while (!q2.empty()) q2.pop();
n = read(), m = read();
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
cc = getchar();
while (cc != '.' && cc != 'Z' && cc != 'G'
&& cc != 'M' && cc != 'X') cc = getchar();
if (cc == 'X') mark[i][j] = 1;
if (cc == 'Z') z[++cntz][0] = i, z[cntz][1] = j;
if (cc == 'M') q1.push((node){
i, j}), vis[i][j] = 1;
if (cc == 'G') q2.push((node){
i, j}), vis[i][j] = 2;
}
while (!q1.empty() || !q2.empty())
{
//vis不用清零,因为如果下一秒那个位置男孩or女孩不能达到了,check也会把它continue出来
ans++; //每一秒
node u, v;
for (int t = 1; t <= 3; t++) //男孩三层(走三次)
for (int j = q1.size(); j >= 1; j--)
//这时的q1.size()不会循环一次改变一次,就可以把循环之前q1里面所有的(上一秒)都处理掉,十分巧妙
{
u = q1.front(); q1.pop();
if (!check (u.x, u.y, ans)) continue;
for (int i = 0; i < 4; i++)
{
v = (node){
u.x + xx[i], u.y + yy[i]};
if (!check (v.x, v.y, ans) || vis[v.x][v.y] == 1)
continue;
if (vis[v.x][v.y] == 2) {
printf ("%d\n", ans); return;}
q1.push(v), vis[v.x][v.y] = 1;
}
}
for (int j = q2.size(); j >= 1; j--)
{
u = q2.front(); q2.pop();
if (!check (u.x, u.y, ans)) continue;
for (int i = 0; i < 4; i++)
{
v = (node){
u.x + xx[i], u.y + yy[i]};
if (!check (v.x, v.y, ans) || vis[v.x][v.y] == 2)
continue;
if (vis[v.x][v.y] == 1) {
printf ("%d\n", ans); return;}
q2.push(v), vis[v.x][v.y] = 2;
}
}
}
printf ("-1\n");
}
int main()
{
T = read();
while (T--) work ();
return 0;
}