hdu-3085-Nightmare Ⅱ(双向BFS+曼哈顿距离)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3085

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.

 

 

Sample Input

 

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

 

 

Sample Output

 

1 1 -1

题目大意:两个人在迷宫中走丢了,迷宫中有良知鬼,鬼会吃人,现在知道他们两个人的位置,和两个鬼的位置,鬼每分钟会向四周分裂,每次都是鬼先分裂,人后走,如果人和鬼在一个房间,人会死,x事墙,'.'是路,鬼可以穿墙,人不能,一个人能走三步,另一个人走一步,每分钟;

如果他们呢能见面,输出最短时间,如果不能,输出-1,

一开始尝试同步刷新鬼的位置,但是后来想了想,鬼的扩散相当于墙,只要人到的位置不是鬼的位置,人行走的距离大于鬼行走的距离即可,这样就不用刷新鬼的范围了,直接判断即可,我们接下来只用两次bfs,第一次找是一个人的能走的范围,第二次是另一个人走的范围,只要他们之间的范围有重叠,那么就说明他们相遇了,两次bfs。

ac:

//一页 27行就很舒服 
#include<stdio.h>
#include<string.h>  
#include<math.h>  
  
//#include<map>   
//#include<set>
#include<deque>  
#include<queue>  
#include<stack>  
#include<bitset> 
#include<string>  
#include<iostream>  
#include<algorithm>  
using namespace std;  

#define ll long long  
#define INF 0x3f3f3f3f  
#define mod 998244353
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b) 
#define clean(a,b) memset(a,b,sizeof(a))// 水印 
//std::ios::sync_with_stdio(false);

struct node{
	int x,y;
	node(int _x=0,int _y=0):x(_x),y(_y){}
};
char map[1000][1000];
int fx[4]={1,-1,0,0},fy[4]={0,0,1,-1};
int n,m,tim,p[2][2],items[2][2];
queue<node> que[2],q;

int len(node e,int i)
{
	return abs(e.x-items[i][0])+abs(e.y-items[i][1]);
}

bool judge_Z(node e)
{
	if(e.x>=0&&e.y>=0&&e.x<n&&e.y<m)//地图中 
	{
		if(map[e.x][e.y]!='X')//不是墙 
		{//没有鬼 
			if(len(e,0)>2*tim&&len(e,1)>2*tim)
				return 1;
		}
	}
	return 0;
}

bool bfs(int k,int num,char op,char ed)
{
	q=que[k];
	while(num--)//走num次 
	{
		while(q.size())
		{
			node a=q.front();
			q.pop();
			que[k].pop();
			if(judge_Z(a)==0)
				continue;
			for(int i=0;i<4;++i)
			{
				node e;
				e.x=a.x+fx[i],e.y=a.y+fy[i];
				if(judge_Z(e)==0||map[e.x][e.y]==op)
					continue;
				if(map[e.x][e.y]==ed)
					return 1;
				map[e.x][e.y]=op;
				que[k].push(e);
			}
		}
		q=que[k];
	}
	return 0;
}

int solve()
{
	while(que[0].size())	que[0].pop();
	while(que[1].size()) 	que[1].pop();
	while(q.size()) 	 	q.pop();
	que[0].push(node(p[0][0],p[0][1]));
	que[1].push(node(p[1][0],p[1][1]));
	tim=0;
	while(que[0].size()&&que[1].size())
	{
		tim++;
		if(bfs(0,3,'M','G')||bfs(1,1,'G','M'))
			return tim;
	}
	return -1;
}

int main()
{
	std::ios::sync_with_stdio(false);
	int t;
	cin>>t;
	while(t--)
	{
		cin>>n>>m;
		int k=0;
		clean(map,'X');
		for(int i=0;i<n;++i)
		{
			for(int j=0;j<m;++j)
			{
				cin>>map[i][j];
				if(map[i][j]=='M')
					p[0][0]=i,p[0][1]=j;//bx=i,by=j;
				if(map[i][j]=='G')
					p[1][0]=i,p[1][1]=j;//gx=i,gy=j;
				if(map[i][j]=='Z')
					items[k][0]=i,items[k++][1]=j;
			}
		}
		cout<<solve()<<endl;
	}
}

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值