双向bfs --HDU - 3085 Nightmare Ⅱ

HDU - 3085 Nightmare Ⅱ:https://vjudge.net/problem/HDU-3085
题意:
G和M在迷宫里寻找对方,M每秒可以走3步,G每次走一步,且只能上下左右走。迷宫里有鬼,鬼每次分裂到上下左右两格位置,直到占满所有格子,鬼可以穿墙,求G和M在不遇到鬼的情况下的最短相遇时间。
思路:
双向bfs,由于M每次走3步,所以M每次要处理3次,这要处理的点就是M每次要走三步,G每次走一步的同步性问题。
由于鬼可以穿墙,所以判断人和鬼是否相遇时根据曼哈顿距离来算就行。当时间time*2<曼哈顿距离时会和鬼相遇,鬼每次往四个方向走两步, 所以time * 2。

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+7;
const int MAXN = 800+10;
 
char maze[MAXN][MAXN];
int n, m, dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
int ghost[2][2];
 
struct node
{
    int x, y;
};
node M, G;
 
bool caught(node now, int time) //判断会不会被ghost抓住,使用曼哈顿距离判断 
{
    if(abs(now.x-ghost[0][0])+abs(now.y-ghost[0][1])<=2*time) return true;
    if(abs(now.x-ghost[1][0])+abs(now.y-ghost[1][1])<=2*time) return true;
    return false;
}
 
queue<node>q[2];
bool vis[2][MAXN][MAXN];
bool bfs(int id, int time)
{
    int Size = q[id].size();    //用于刹车,防止把新入队的点也进行更新 
    node now, tmp;
    while(Size--)
    {
        now = q[id].front();
        q[id].pop();
 
        if(caught(now, time)) continue;   //欲出发的点会被ghost抓住, 下一个
        for(int i = 0; i<4; i++)
        {
            tmp.x = now.x + dir[i][0];
            tmp.y = now.y + dir[i][1];
            if(tmp.x>=1 && tmp.x<=n && tmp.y>=1 && tmp.y<=m   //没出界
               && maze[tmp.x][tmp.y]!='X' && maze[tmp.x][tmp.y]!='Z'   //可行通道
               && !vis[id][tmp.x][tmp.y] && !caught(tmp, time))   //没有被访问过,其此时此地不会被抓
            {
                vis[id][tmp.x][tmp.y] = true;
                 //对方已经访问过,则meet。不需判断两者到达的时间是否相等,因为可以走0步,所以就可以一直停留
                if(vis[!id][tmp.x][tmp.y]) return true;
                q[id].push(tmp);
 
            }
        }
    }
    return false;
}
 
int solve()
{
    memset(vis, 0, sizeof(vis));
    while(!q[0].empty()) q[0].pop();
    while(!q[1].empty()) q[1].pop();
    vis[0][M.x][M.y] = 1;
    vis[1][G.x][G.y] = 1;
    q[0].push(M);
    q[1].push(G);
 
    int time = 0;   //计时器
    while(!q[0].empty() || !q[1].empty())
    {
        time++;
        for(int i = 1; i<=3; i++)   //M在一秒内,可以走0、1、2、3步
            if(bfs(0, time)) return time;
        if(bfs(1, time)) return time;  //G只能走0、1步
    }
    return -1;
}
 
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &n, &m);
        for(int i = 1; i<=n; i++)
            scanf("%s", maze[i]+1);
 
        int cnt = 0;
        for(int i = 1; i<=n; i++)
        for(int j = 1; j<=m; j++)
        {
           if(maze[i][j]=='Z') ghost[cnt][0] = i, ghost[cnt++][1] = j;
           if(maze[i][j]=='M') M.x = i, M.y = j;
           if(maze[i][j]=='G') G.x = i, G.y = j;
        }
        cout<< solve() <<endl;
    }
}
发布了92 篇原创文章 · 获赞 7 · 访问量 3754

猜你喜欢

转载自blog.csdn.net/dajiangyou123456/article/details/104100862