Problem Description

Last night, little erriyue had a horrible nightmare. He dreamed that he and his girl friend were trapped in a big maze separately. More terribly, there are two ghosts in the maze. They will kill the people. Now little erriyue wants to know if he could find his girl friend before the ghosts find them.
You may suppose that little erriyue and his girl friend can move in 4 directions. In each second, little erriyue can move 3 steps and his girl friend can move 1 step. The ghosts are evil, every second they will divide into several parts to occupy the grids within 2 steps to them until they occupy the whole maze. You can suppose that at every second the ghosts divide firstly then the little erriyue and his girl friend start to move, and if little erriyue or his girl friend arrive at a grid with a ghost, they will die.

Note: the new ghosts also can devide as the original ghost.

Input

The input starts with an integer T, means the number of test cases.

Each test case starts with a line contains two integers n and m, means the size of the maze. (1<n, m<800)

The next n lines describe the maze. Each line contains m characters. The characters may be:

‘.’ denotes an empty place, all can walk on.

‘X’ denotes a wall, only people can’t walk on.

‘M’ denotes little erriyue

‘G’ denotes the girl friend.

‘Z’ denotes the ghosts.

It is guaranteed that will contain exactly one letter M, one letter G and two letters Z.

Output

Output a single integer S in one line, denotes erriyue and his girlfriend will meet in the minimum time S if they can meet successfully, or output -1 denotes they failed to meet.

SampleInput

3
5 6
XXXXXX
XZ..ZX
XXXXXX
M.G...
......
5 6
XXXXXX
XZZ..X
XXXXXX
M.....
..G... 10 10
..........
..X.......
..M.X...X.
X.........
.X..X.X.X.
.........X
..XX....X.
X....G...X
...ZX.X...
...Z..X..X

SampleOutput

1
1
-1 题意就是给你一个迷宫,不对,就是说你现在被困在迷宫里,要去和你GF见面,但是迷宫中还有人不可以走的墙和会杀死人的幽灵,幽灵每个单位时间都会往上下左右延申新的幽灵。
幽灵有两个,M是你的位置,G是GF的位置。
幽灵每秒可以延申两格,你可以每秒走三步,GF每秒只能走一步,如果在不被杀死的情况和女朋友汇合就输出最小单位时间,否则输出-1.
(注意幽灵是可以往墙上延申的)
因为两个人都可以动,不用说,双向BFS是肯定的,不过有一点就是,如何实现每秒走三步以及判断是否被杀死呢?
答案是我也不知道。这道题目就留给各位自己思考。
=7=嘻嘻 不闹了。其实可以换个思路去思考,我们可以用三个bfs代替走三步,但是如何判断是否被杀死呢,其实这道题可以不需要判断是否被杀死,而是判断人物走到能否在幽灵延申到某个位置之前走到那个位置,用曼哈顿距离判断就行了。 提一下什么是曼哈顿距离
常用距离度量方法有十一种,而我们大部分时间只用到欧氏距离和曼哈顿距离。
设两个点的坐标(X1,Y1),(X2,Y2);
欧氏距离就是坐标的直线距离 = sqrt((X2 - X1)2+(Y2 - Y1)2)
而曼哈顿距离就是以欧式距离为斜边构造直角三角形的两直角边和 = |X2 - X1| + |Y2 - Y1|
为什么有这么多构造方式以及其区别,这篇博文就不详细介绍了。 值得一题的是,因为是双向搜索,所以需要开两个二维数组或是一个三维数组分别标记你或者GF是否走过。
还有就是代码BFS中的
 int len = q[w].size();
while(len--)

因为我们不是一次就搜索完,我们的BFS仅仅只是做走一步的作用,所以只把当前已经存的点的下一点存入就行了。若是觉得难以理解可以替换成while(!q[w].empty)观察每一步的输出情况。

代码:
 #include <iostream>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <sstream>
#include <iomanip>
#include <map>
#include <stack>
#include <deque>
#include <queue>
#include <vector>
#include <set>
#include <list>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <iterator>
#include <cmath>
#include <bitset>
#include <ctime>
#include <fstream>
#include <limits.h>
#include <numeric> using namespace std; #define F first
#define S second
#define mian main
#define ture true #define MAXN 1000000+5
#define MOD 1000000007
#define PI (acos(-1.0))
#define EPS 1e-6
#define MMT(s) memset(s, 0, sizeof s)
typedef unsigned long long ull;
typedef long long ll;
typedef double db;
typedef long double ldb;
typedef stringstream sstm;
const int INF = 0x3f3f3f3f; int fx[][]={,,-,,,,,-};
char mp[][];
int vis[][][];
int gx,gy,mx,my,n,m,step;  //记录坐标,这里的step指的是GF走的步数,应该理解成走了多少单位时间
pair<int,int>cur,z[];  //z用来记录幽灵位置
queue<pair<int,int> >q[]; //分别记录你和GF的路径 bool check(pair<int,int> x){
if(x.F < || x.S < || x.F >= n || x.S >= m || mp[x.F][x.S] == 'X')
return false;
if((abs(x.F-z[].F)+abs(x.S-z[].S)) <= *step || (abs(x.F-z[].F)+abs(x.S-z[].S)) <= *step) //判断在幽灵延申到某个点之前是否能走到
return false;
return true;
} int bfs(int w){
pair<int,int>tp,next;
int len = q[w].size();
while(len--){  //注意这里不是搜完,因为是多次搜索,只需要把当前步骤行进完就行了
tp = q[w].front();
q[w].pop();
if(!check(tp)) continue;
for(int i = ; i < ; i++){
next.F = tp.F + fx[i][];
next.S = tp.S + fx[i][];
if(!check(next))
continue;
if(!vis[w][next.F][next.S]){
if(vis[-w][next.F][next.S]) //判断下一个点是否对方已经走过
return ;
vis[w][next.F][next.S] = ;
q[w].push(next);
}
}
}
return ;
} int solve(){
while(!q[].empty())
q[].pop();
while(!q[].empty())
q[].pop(); cur.F = mx;
cur.S = my;
q[].push(cur);
cur.F = gx;
cur.S = gy;
q[].push(cur);
MMT(vis);
vis[][mx][my] = vis[][gx][gy] = ;
step = ; while((!q[].empty()) || (!q[].empty())){
step++;
if(bfs()) //通过三次bfs达到走三步
return step;
if(bfs())
return step;
if(bfs())
return step;
if(bfs())
return step;
}
return -;
} int main(){
ios_base::sync_with_stdio(false);
cout.tie();
cin.tie();
int t;
cin>>t;
while(t--){
int cnt = ;
cin>>n>>m;
for(int i = ; i < n; i++)
cin>>mp[i];
for(int i = ; i < n; i++)
for(int j = ; j < m; j++){
if(mp[i][j] == 'G')
gx = i, gy = j;
if(mp[i][j] == 'M')
mx = i, my = j;
if(mp[i][j] == 'Z')
z[cnt].F = i, z[cnt++].S = j;
}
cout << solve() << endl;
}
return ;
}

Nightmare Ⅱ(双向BFS)的更多相关文章

  1. HDU 3085 Nightmare Ⅱ (双向BFS)

    Nightmare Ⅱ Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  2. HDU3085 Nightmare Ⅱ —— 双向BFS + 曼哈顿距离

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3085 Nightmare Ⅱ Time Limit: 2000/1000 MS (Java/Other ...

  3. HDU 3085 Nightmare Ⅱ 双向BFS

    题意:很好理解,然后注意几点,男的可以一秒走三步,也就是三步以内的都可以,鬼可以穿墙,但是人不可以,鬼是一次走两步 分析:我刚开始男女,鬼BFS三遍,然后最后处理答案,严重超时,然后上网看题解,发现是 ...

  4. HDU3085 Nightmare Ⅱ (双向BFS)

    联赛前该练什么?DP,树型,状压当然是爆搜啦 双向BFS就是两个普通BFS通过一拼接函数联系,多多判断啦 #include <iostream> #include <cstdio&g ...

  5. HDU 3085 Nightmare II 双向bfs 难度:2

    http://acm.hdu.edu.cn/showproblem.php?pid=3085 出的很好的双向bfs,卡时间,普通的bfs会超时 题意方面: 1. 可停留 2. ghost无视墙壁 3. ...

  6. HDU 3085 Nightmare Ⅱ(双向BFS)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3085 题目大意:给你一张n*m地图上,上面有有 ‘. ’:路 ‘X':墙 ’Z':鬼,每秒移动2步,可 ...

  7. HDU3085(双向BFS+曼哈顿距离)题解

    Nightmare Ⅱ Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  8. BFS:HDU3085-Nightmare Ⅱ(双向BFS)

    Nightmare Ⅱ Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 32768/32768 K (Java/Others) Tot ...

  9. POJ1915Knight Moves(单向BFS + 双向BFS)

    题目链接 单向bfs就是水题 #include <iostream> #include <cstring> #include <cstdio> #include & ...

随机推荐

  1. 如何调教你的博客Episode1——修改整体样式

    如图所示,这是你刚刚注册的博客园博客,让我们开始一步步修改它. 1.写入自适应代码 html,body{ height:100%; border:; margin:; padding:; } body ...

  2. Java 在spring cloud中使用Redis,spring boot同样适用

    1.本地安装redis服务,官网下载. 2.在开发中要使用redis,首先要启动本地redis服务,启动后页面如下: 3.在spring boot项目pom.xml文件中添加Redis需要的依赖包,可 ...

  3. c语言实现基本的数据结构(三) 栈

    #include <stdio.h> #include <tchar.h> #include <stdlib.h> #define StackSize 5 #def ...

  4. Scrum Master如何让敏捷团队正常运转?

    官方<Scrum指南>中定义:Scrum Master在Scrum团队中属于服务型领导,负责践行和支持<Scrum指南>中定义的Scrum,要帮团队的每个人理解Scrum理论. ...

  5. java 判断 string 转 integer 判断

    NumberUtils.isDigits("1") NumberUtils.isDigits("/") 根据返回 true false 再确定是否转换即可 需要 ...

  6. Linux下Tomcat的搭建以及开机自启动设置

    首先进行下JDK的配置: 1.查看下系统信息,确认是32位还是64位:uname -a 2.下载相应位数的jdk压缩包,传到Linux系统,这里提供一个32位和64位的下载链接:https://pan ...

  7. 拖动水滴给土地浇水(CocosCreator)

    推荐阅读:  我的CSDN  我的博客园  QQ群:704621321 一.前沿       最近在做农场的模块,需要实现拖动水滴图标(

  8. Mac添加中国法定节假日安排

    最近中秋.国庆临近,当大家开始抢票才反应过来,原来假日已然临近,打开mac日历,发现并没有标注节假日安排,发现了这篇文章,写了这篇读后感. 上面的文章介绍使用了两种在苹果系列设备设置中国节假日的方式: ...

  9. dataGrip连接数据库失败[08001]的一种可能原因

      我使用的是mac系统,并且由于机型较老,容量不高,为减轻系统负荷,没有设置开机自动启动MYSQL服务.这导致我在一次重启后,重新开启服务,然后就出现了dataGrip连接不上数据库: 在网上查找相 ...

  10. vue路由菜单权限设置就button权限设置

    路由权限的设计思路: 首先,我们的需要校验权限的路由的 url,全部由后端返回,后端会返回当前用户的路由树数组.前端在进入页面前请求接口,把数据拿到: 其次,前端会维护一个路由映射组件的列表,如果路由 ...