HDU-3085 Nightmare Ⅱ (双BFS)

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

题意:一天晚上,小erriyue做了一个可怕的噩梦。他梦见他和他的女朋友被困在一个大的迷宫里。更可怕的是,在迷宫里有两个鬼。他们会杀人。现在小erriyue想知道他能否在鬼找他们前找到他的女朋友。
你可能认为小erriyue和他的女朋友可以在4个方向移动。在每一秒,小erriyue可以移动3步和他的女朋友可以移动1步。鬼是邪恶的,每一秒,他们将分为几个部分,占领距离他们为2的地方,直到他们占据整个迷宫。你可以假设两个鬼鬼先于小erriyue和他的女朋友开始移动,如果小erriyue或他的女朋友到达一个幽灵网格,他们会死。
注:新鬼也可以分身,并且鬼会穿墙。

思路:只要他们到达其中一个人走过的地方就算他们已经相遇。从M、G双向广搜,鬼是先分身,人再移动的,因为M一个单位时间可以移动三步,所以会拓展出来很多新的节点,在每次广搜前,先读入上次的数据判断,两个人分成两个队列进行处理。判断鬼到人距离的时候只要计算人与两个鬼的曼哈顿距离即可。

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
int dir[4][2]={1,0,-1,0,0,1,0,-1};
int n,m,step;
char Map[810][810];
struct node
{
    int x,y;
}gg,mm,zz[2];
queue<node>q[2],qt;
int judge(node t)
{
    //原始鬼到人的距离
    for(int i=0;i<2;i++)
        if((abs(zz[i].x-t.x)+abs(zz[i].y-t.y))<=2*step||Map[t.x][t.y]=='X'||t.x<0||t.x>=n||t.y<0||t.y>=m)
        return 0;
    return 1;
}
//男的可以走三步以内的任意步数
int bfs(int mark,int num,char start,char endd)
{
        node a,b;
        qt=q[mark];//把当前队列付给qt
        for(int i=0;i<num;i++)//方圆num以内都可以在一个单位时间内走到
        {
            while(!qt.empty())
            {
                a=qt.front();
                qt.pop();
                q[mark].pop();
                if(!judge(a)) continue;//因为鬼先走,所以要先判断鬼到人的距离
                for(int j=0;j<4;j++)
                {
                    b=a;
                    b.x+=dir[j][0];
                    b.y+=dir[j][1];
                    //Map[b.x][b.y]==start相当于vis 标记这个点是否被走过
                    if(!judge(b)||Map[b.x][b.y]==start) continue;
                    //当一个人走到另一个人已经走到过的点,这就算他们已经相遇
                    if(Map[b.x][b.y]==endd) return 1;
                    Map[b.x][b.y]=start; //标记这个点被M或G走过
                    q[mark].push(b);
                }
            }
            qt=q[mark];
        }
        return 0;
}
int Solve()
{
    step=0;
    while(!q[0].empty()) q[0].pop();
    while(!q[1].empty()) q[1].pop();
    while(!qt.empty()) qt.pop();
    q[0].push(mm), q[1].push(gg);
    while(!q[0].empty()&&!q[1].empty())
    {
        step++;
        if(bfs(0,3,'M','G')||bfs(1,1,'G','M'))
            return step;
    }
    return -1;
}
int main()
{
    int i,j,k,t;
    scanf("%d",&t);
    while(t--)
    {
        memset(Map,'X',sizeof(Map));
        scanf("%d%d",&n,&m);
        k=0;
        for(i=0;i<n;i++)
        {
            scanf("%s",Map[i]);
            for(j=0;j<m;j++)
            {
                if(Map[i][j]=='M')
                    mm.x=i,mm.y=j;
                if(Map[i][j]=='G')
                    gg.x=i,gg.y=j;
                if(Map[i][j]=='Z')
                {
                    zz[k].x=i;
                    zz[k].y=j;
                    k++;
                }
            }
        }
        printf("%d\n",Solve());
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值