HDU 3085 Nightmare 双向BFS

HDU 3085 Nightmare


题目大意:

  • 在一个有一个会以速度 2 自动分裂的 ghost 的有墙壁的迷宫里
  • 给两个速度分别为1,3的点 G , M , 问能否在不碰到 ghost 的情况下相遇
  • 在一秒内,ghost分裂后 , G , M 再移动
  • 若可以相遇输出时间,不能相遇输出-1

解题过程:

  • 刚开始写了一个纯的bfs , 对 ghost 的到每个地方的时间bfs求出来,然后再bfs求出其中一个人合法到达每个地方的时间,再用bfs判断另一个人是否可以合法地碰到前面那个人,结果超时了.
  • 优化:
    • (1)ghost的位置其实是曼哈顿距离,省去了第一次的bfs
    • (2)两个人的位置交替bfs,即双向bfs,又省去了一次bfs
    • *

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include <cstring>
#define rep(i,l,p) for (int i = l;i<=p;i++)
#define drep(i,p,l) for (int i = p;i>=l;i--)
#define fread() freopen("in.txt","r",stdin)
using namespace std;

const int dx[4] = {0,0,1,-1};
const int dy[4] = {1,-1,0,0};
int n,m,step;
char Map[805][805];
struct Node
{
    int x,y;
    Node(int _,int __):x(_),y(__){}
    Node(){}
}gg,mm,z[2];
bool legal(int x,int y){
    rep(i,0,1) if(abs(z[i].x - x) + abs(z[i].y - y) <= 2*step ) {
        return false;
    }
    if(x<1 || x>n || y<1 || y>m || Map[x][y] == 'X') return false;

    return true;
}
bool bfs(queue<Node> &q,int num,char st,char ed){
    queue<Node> qt;
    rep(i,1,num){
        while(!q.empty()){

            int x = q.front().x,y = q.front().y;
            q.pop();
            if(!legal(x,y)) continue;
            rep(i,0,3){
                int xx = x+dx[i],yy = y+dy[i];
                if(!legal(xx,yy) || Map[xx][yy]==st) continue;
                if(Map[xx][yy] == ed) {
                    return true;
                }
                Map[xx][yy] = st;
                qt.push(Node(xx,yy));
            }

        }
        q = qt;
    }
    return false;
}
int solve(){
    queue<Node> que[2];
    que[0].push(gg);
    que[1].push(mm);
    step = 0;
    while( !que[1].empty() || !que[1].empty()){

        step++;
        if(bfs(que[0],1,'G','M') || bfs(que[1],3,'M','G') ){
            return step;
        }
    }
    return -1;
}
inline void init(){
    cin >> n >> m;
    int cnt = 0;
    rep(i,1,n) cin >> Map[i]+1;
    rep(i,1,n){
        rep(j,1,m){
            if(Map[i][j] == 'Z') {z[cnt].x = i; z[cnt].y = j; cnt++;} // !!!
            else if(Map[i][j] == 'G') gg.x = i,gg.y = j;
            else if (Map[i][j] == 'M') mm.x = i,mm.y = j;
        }
    }
}
int main(int argc, char const *argv[])
{
    // fread();
    std::ios::sync_with_stdio(false);
    int T;
    cin >> T;
    while(T--){
        init();
        cout << solve() << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值