噩梦

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;
}
posted @ 2021-02-14 21:17  C2022lihan  阅读(57)  评论(0编辑  收藏  举报