噩梦
1.前言
鬼畜的题意,真的成了我的噩梦
2.题解
这道题中,小
e
r
r
i
y
u
e
erriyue
erriyue的3步是可以漂移转弯的,我因为这个差点顺网线去打爆出题人的狗头。
(1).法1
首先我尝试了一下我们之前的写法,用一个 f l a g flag flag标记正反,可是我很快发现:男生的拓展非常麻烦,因为只满足曼哈顿距离小于 3 3 3也不对,因为路径上可能会出现不可路过的点,所以必须老老实实的用 d f s dfs dfs或 b f s bfs bfs跑,但是防止跑重复的点很麻烦,因为重置标记非常耗时间,妥妥的 T L E TLE TLE,但如果不重置的话会 W A WA WA,因为走到这个点的步数不同的路径花费不一样,经过我的慎重考虑,我决定——————不标记,直接暴力跑,可以很高兴的宣布结果, T L E TLE TLE,所以这个方法代码实现十分麻烦
(2).法2(新get到的一个不错的技巧)
男生一个队列,女生一个队列。女生的更新照旧,男生的更新 3 3 3步一组,但是不能这样写
//伪代码
for (int i = 1; i <= 3; i++) {
while (q_boy.size ()) {
//拓展
}
}
因为这样写的话把已经拓展的东西也加入了队列,就不知道拓展了几次
代码十分好写,细节见代码
参考代码
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define ULL unsigned long long
using namespace std;
template <typename T> int read (T &x) {x = 0; T f = 1;char tem = getchar ();while (tem < '0' || tem > '9') {if (tem == '-') f = -1;tem = getchar ();}while (tem >= '0' && tem <= '9') {x = (x << 1) + (x << 3) + tem - '0';tem = getchar ();}x *= f; return 1;}
template <typename T> void write (T x) {if (x < 0) {x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }
const int Maxn = 800;
int Times, n, m;
int ans[2][Maxn + 5][Maxn + 5];//ans[1][i][j]记录男生走到 (i, j)的最少步数,ans[2][i][j]同理
char c[Maxn + 5][Maxn + 5];//地图
int tox[10] = {0, 1, -1, 0, 0};
int toy[10] = {0, 0, 0, 1, -1};
int tot;
struct node {
int step, x, y, Up;
bool flag;
}s, t, z[4];
queue <node> qb, qg;
int Dis (node x, node y) {//曼哈顿距离
return Abs (x.x - y.x) + Abs (x.y - y.y);
}
int Two_Way_Bfs () {
while (qb.size ()) qb.pop ();//男生队列清空
while (qg.size ()) qg.pop ();//女生队列清空
qb.push (s); qg.push (t);
memset (ans, -1, sizeof ans);
ans[s.flag][s.x][s.y] = ans[t.flag][t.x][t.y] = 0;//初始化
while (qb.size () || qg.size ()) {
int step;
if (qb.size ())//如果男生还能走
step = qb.front ().step;
for (int i = 1; i <= 3; i++) {//拓展三次(关键代码)
for (int j = qb.size (); j; j--) {//固定取出次数 qb.size (),保证同一个i下取出的步数一样 (巧妙点)
node Now = qb.front (), Next; qb.pop ();
if (Dis (Now, z[1]) <= 2 * step + 2 || Dis (Now, z[2]) <= 2 * step + 2) continue;//被鬼抓到
Next = Now; Next.step = step + 1;
for (int k = 1; k <= 4; k++) {
int x = Now.x + tox[k], y = Now.y + toy[k];
Next.x = x; Next.y = y;
if (x < 1 || x > n) continue;
if (y < 1 || y > m) continue;
if (c[x][y] == 'X') continue;
if (ans[Next.flag][x][y] != -1) continue;
if (Dis (Next, z[1]) <= 2 * Next.step || Dis (Next, z[2]) <= 2 * Next.step) continue;
if (ans[Next.flag ^ 1][Next.x][Next.y] != -1) //如果女生能走到这里
return Max (Next.step, ans[Next.flag ^ 1][Next.x][Next.y]);
ans[Now.flag][x][y] = Next.step;//记录路径
qb.push (Next);
// printf ("x = %d, y = %d, flag = %d, step = %d, Up = %d\n", Next.x, Next.y, Next.flag, Next.step, Next.Up);
}
}
}
//女生的同理,作者咕掉
if (qg.size ())
step = qg.front ().step;
for (int i = 1; i <= 1; i++) {
for (int j = qg.size (); j; j--) {
node Now = qg.front (), Next; qg.pop ();
if (Dis (Now, z[1]) <= 2 * step + 2 || Dis (Now, z[2]) <= 2 * step + 2) continue;
Next = Now; Next.step = step + 1;
for (int k = 1; k <= 4; k++) {
int x = Now.x + tox[k], y = Now.y + toy[k];
Next.x = x; Next.y = y;
if (x < 1 || x > n) continue;
if (y < 1 || y > m) continue;
if (c[x][y] == 'X') continue;
if (ans[Next.flag][x][y] != -1) continue;
if (Dis (Next, z[1]) <= 2 * Next.step || Dis (Next, z[2]) <= 2 * Next.step) continue;
if (ans[Next.flag ^ 1][Next.x][Next.y] != -1)
return Max (Next.step, ans[Next.flag ^ 1][Next.x][Next.y]);
ans[Now.flag][x][y] = Next.step;
qg.push (Next);
// printf ("x = %d, y = %d, flag = %d, step = %d, Up = %d\n", Next.x, Next.y, Next.flag, Next.step, Next.Up);
}
}
}
}
return -1;
}
int main () {
scanf ("%d", &Times);
while (Times--) {
tot = 0;
scanf ("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf ("%s", c[i] + 1);
for (int j = 1; j <= m; j++) {
if (c[i][j] == 'M') {//找到男生的位置
s.step = 0;
s.x = i;
s.y = j;
s.flag = 1;
s.Up = 3;
}
if (c[i][j] == 'G') {//找到女生的位置
t.step = 0;
t.x = i;
t.y = j;
t.flag = 0;
t.Up = 1;
}
if (c[i][j] == 'Z') {//找到鬼的位置
z[++tot].x = i;
z[tot].y = j;
}
}
}
cout << Two_Way_Bfs () << endl;
}
return 0;
}