hdu-3085(双向bfs)

题目大意:
ghosts先每次分裂会覆盖两步之内所有的地方,然后erriyue每次走三步,girl friend每次走一步,ghosts能穿墙,人不能,问erriyue和girl friend是否能在指定的时间内相遇。
特别要注意的是,可以选择不走!不是一定要在那个时刻相遇! 英语渣,没读出来,但看别人的代码又确实是这个意思。

我一开始打算让幽灵也bfs,觉得这样不好写,搜网上有人用曼哈顿距离做,学习了一发。

比如说图上的两个黑点,分别表示当前的“我”(可以是erriyue,也可以是girl friend)和幽灵的初始位置,红蓝黄线都可以表示我到幽灵的曼哈顿距离,因为幽灵每次可以走两步,所以只要我到幽灵的曼哈顿距离小于二倍的已经走的次数,我就不会和幽灵相遇。

这里写图片描述

至于双向bfs我觉得和单向的区别不大,就是要注意交替逐层搜索,每次搜完都要判断一下。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;

const int tox[] = {0,1,0,-1};
const int toy[] = {1,0,-1,0};
char str[805][805];
int used[2][805][805];
int n,m,step;

struct node
{
    int x,y;
} err,gf,z[2]; //分别表示初末位置,和两个小鬼的位置

queue<node> q[2];

void init()
{
    int cnt=0;
    scanf("%d%d",&n,&m);
    for(int i=0; i<n; i++)
    {
        scanf("%s",str[i]);
        for(int j=0; j<m; j++)
        {
            if(str[i][j] =='M') //记录初末位置
            {
                err.x = i;
                err.y = j;
            }
            else if(str[i][j] =='G')
            {
                gf.x = i;
                gf.y = j;
            }
            else if(str[i][j] =='Z')
            {
                z[cnt].x = i;
                z[cnt++].y = j; //下次是第二个小鬼
            }
        }
    }
}

int judge(node b)
{
    if(b.x<0 || b.y<0 || b.x>=n || b.y>=m || str[b.x][b.y] =='X')
        return 0;
    if((abs(b.x-z[0].x) + abs(b.y-z[0].y)) <= 2*step)
        return 0;
    if((abs(b.x-z[1].x) + abs(b.y-z[1].y)) <= 2*step) //用曼哈顿距离表示 是否会碰到分裂的小鬼
        return 0;
    return 1;
}

int bfs(int w)
{
    node one,next;
    int sum;
    sum = q[w].size();
    while(sum--)
    {
        one = q[w].front();
        q[w].pop();
        if(judge(one) == 1)
        {
            for(int i=0; i<4; i++)
            {
                next.x = one.x + tox[i];
                next.y = one.y + toy[i];
                if(judge(next) == 0)
                    continue;
                if(used[w][next.x][next.y] == 0)
                {
                    if(used[w^1][next.x][next.y] == 1) //位运算w=0,这里就是1,w=1,这里就是0,判断两个人遇到了没
                        return 1;
                    used[w][next.x][next.y] = 1;
                    q[w].push(next);
                }
            }
        }
    }
    return 0;
}
int solve()
{
    while(!q[0].empty())
        q[0].pop();
    while(!q[1].empty())
        q[1].pop();

    q[0].push(err);
    q[1].push(gf);
    memset(used,0,sizeof(used));
    used[0][err.x][err.y]=used[1][gf.x][gf.y]=1;
    step=0;

    while ((!q[0].empty()) || (!q[1].empty()))
    {
        step++;
        if (bfs(0)==1)
            return step;
        if (bfs(0)==1)
            return step;
        if (bfs(0)==1) //走三步
            return step;
        if (bfs(1)==1) //走一步
            return step;
    }
    return -1;
}
int main()
{
    int Case;
    scanf("%d",&Case);
    while (Case--)
    {
        init();
        printf("%d\n",solve());
    }
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值