一、内容
给定一张N*M的地图,地图中有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
二、思路
- 已知起点(男孩),终点(女孩)进行双向bfs。
- 由于题目给出男孩每秒钟可以走3步,所以每次循环将队列里面前一步的状态循环完,循环3次等于走了3步。
- 检查与鬼的距离,预先判断某个点是否会被鬼给波及。
- vis数组记录走过该点的状态, 0表示未走过,1表示男孩走过,2表示女孩走过。
三、代码
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <iostream>
using namespace std;
const int N = 805;
int t, n, m, vis[N][N], zx1, zy1, zx2, zy2, mx, my, gx, gy, step;
char G[N][N];
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
struct node {
int x, y;
node(int xx, int yy) {
x = xx; y = yy; ;
}
};
bool ok(int x, int y) {
if (x < 0 || y < 0 || x >= n || y >= m || G[x][y] == 'X') return false;
//看能不能被鬼覆盖
if (abs(x - zx1) + abs(y - zy1) <= 2 * step) return false;
if (abs(x - zx2) + abs(y - zy2) <= 2 * step) return false;
return true;
}
int bfs() {
memset(vis, 0, sizeof(vis));
//标记状态 0表示未访问 1表示男孩 2表示女孩访问
vis[mx][my] = 1;
vis[gx][gy] = 2;
step = 0;
//初始化时间
queue<node> qm, qg;
qm.push(node(mx, my));
qg.push(node(gx, gy));
while (!qm.empty() && !qg.empty()) {
step++;
//男孩走3步
for (int k = 0; k < 3; k++) {
for (int i = 0, len = qm.size(); i < len; i++) {
node t = qm.front();
qm.pop();
//判断一下刚出来的点是否能动
if (!ok(t.x, t.y)) continue;
for (int j = 0; j < 4; j++) {
int fx = t.x + dx[j];
int fy = t.y + dy[j];
if (!ok(fx, fy) || vis[fx][fy] == vis[t.x][t.y]) continue;
//看该点符合要求否 避免重复走
if (vis[fx][fy] + vis[t.x][t.y] == 3) {
//找到答案
return step;
}
vis[fx][fy] = vis[t.x][t.y];
qm.push(node(fx, fy));
}
}
}
//女孩走一步
for (int i = 0, len = qg.size(); i < len; i++) {
node t = qg.front();
qg.pop();
if (!ok(t.x, t.y)) continue;
for (int j = 0; j < 4; j++) {
int fx = t.x + dx[j];
int fy = t.y + dy[j];
if (!ok(fx, fy) || vis[fx][fy] == vis[t.x][t.y]) continue;
if (vis[fx][fy] + vis[t.x][t.y] == 3) {
//找到答案
return step;
}
vis[fx][fy] = vis[t.x][t.y];
qg.push(node(fx, fy));
}
}
}
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]);
}
//找出男女鬼的位置
int cnt = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (G[i][j] == 'Z') {
if (!cnt){
zx1 = i; zy1 = j;
cnt++;
} else {
zx2 = i; zy2= j;
}
}
if (G[i][j] == 'M') mx = i, my = j;
if (G[i][j] == 'G') gx = i, gy = j;
}
}
printf("%d\n", bfs());
}
return 0;
}