HDU3085NightmareII题解--双向BFS

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=3085

分析

大意就是一个男孩和一个女孩在网格里,同时还有两个鬼,男孩每轮走三步,女孩每轮走一步,与鬼曼哈顿距离不超过2*轮数的区域都被鬼占领,问男孩女孩最少多少轮相遇?

这题显然用双向BFS,男孩每轮拓展3次,女孩每轮拓展1次,一个记录女孩走过哪些地方,另一个记录男孩,有个地方被两人都走过就输出答案

然后一开始我就发现我的BFS写得代码又臭又长,后面看一位大佬博客才学到简洁的操作

代码

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <iostream>
#define ll long long 
#define ri register int
using std::min;
using std::max;
using std::swap; 
using std::queue;
template <class T>inline int abs(int  x){
    return x<0?-x:x;
}
template <class T>inline void read(T &x){
    x=0;int ne=0;char c;
    while(!isdigit(c=getchar()))ne=c=='-';
    x=c-48;
    while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
    x=ne?-x:x;return ;
}
const int maxn=805;
const int inf=0x7fffffff;
const int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int g[maxn][maxn];
int n,m,T;
int sx,sy,tx,ty;
int gx1,gx2,gy1,gy2;
char str[maxn];
struct Dat{
    int x,y;
    Dat (int _x,int _y){x=_x,y=_y;}
    Dat () {x=y=0;}
};
int cnt=1,dis;
bool wtf=0;
bool vis1[maxn][maxn],vis2[maxn][maxn];
bool check(int x,int y){
    //if(wtf)printf("** %d %d %d %d %d %d\n",x,y,cnt,dis,abs(x-gx1)+abs(y-gy1),abs(x-gx2)+abs(y-gy2));
    if(x>=1&&x<=n&&y>=1&&y<=m&&g[x][y]!=1&&(abs(x-gx1)+abs(y-gy1))>dis&&(abs(x-gx2)+abs(y-gy2))>dis)return 1;
    return 0;
}
inline void bfs(){
    int x,y,xx,yy;
    int x1,x2,x3,y1,y2,y3,x4,y4;
    queue <Dat> q1,q2;
    while(q1.size())q1.pop();
    while(q2.size())q2.pop();
    q1.push(Dat(sx,sy));
    q2.push(Dat(tx,ty));
    cnt=1,dis=2;
    int l1=1,r1=1,l2=1,r2=1,lst=0;
    memset(vis1,0,sizeof(vis1));
    memset(vis2,0,sizeof(vis2));
    vis1[sx][sy]=vis2[tx][ty]=1;
    while(q1.size()&&q2.size()){wtf=0;          
        for(ri k=1;k<=3;k++){
            lst=r1;     
            while(l1<=lst){
                x=q1.front().x,y=q1.front().y;q1.pop();
                l1++;
                if(!check(x,y))continue;
                //printf("1 %d %d\n",x,y);
                for(ri i=0;i<4;i++){
                    xx=x+dx[i],yy=y+dy[i];
                    if(!check(xx,yy)||vis1[xx][yy])continue;
                    q1.push(Dat(xx,yy));
                    if(vis2[xx][yy]){
                        //printf("--%d %d %d\n",cnt,xx,yy);
                        printf("%d\n",cnt);
                        return ;
                    }
                    vis1[xx][yy]=1;
                    r1++;
                }
            }
        }   
        lst=r2;wtf=1;
        while(l2<=lst){
            x=q2.front().x,y=q2.front().y;q2.pop();//printf("%d %d\n",l2,lst);
            l2++;
            if(!check(x,y))continue;            
            for(ri i=0;i<4;i++){
                xx=x+dx[i],yy=y+dy[i];
                if(!check(xx,yy)||vis2[xx][yy])continue;
                q2.push(Dat(xx,yy));//printf("2 %d %d\n",xx,yy);
                if(vis1[xx][yy]){
                    printf("%d\n",cnt);
                    return ;
                }
                vis2[xx][yy]=1;
                r2++;
            }
            //printf("*** %d %d %d\n",l2,r2,lst);
        }
        cnt++;
        dis=cnt*2;
    }
    puts("-1");
    return ;
}
int main(){
    read(T);
    while(T--){
        read(n),read(m);
        gx1=gy1=inf;
        for(ri i=1;i<=n;i++){
            scanf("%s",str+1);
            for(ri j=1;j<=m;j++){
                vis1[i][j]=0,vis2[i][j]=0;
                if(str[j]=='.')g[i][j]=0;
                else if(str[j]=='X')g[i][j]=1;
                else if(str[j]=='M'){
                    g[i][j]=2;
                    sx=i,sy=j;
                }
                else if(str[j]=='G'){
                    g[i][j]=3;
                    tx=i,ty=j;
                }
                else if(str[j]=='Z'){
                    if(gx1==inf)gx1=i,gy1=j;
                    else gx2=i,gy2=j;
                }
            }
        }
        //printf("%d %d %d %d %d %d %d %d\n",sx,sy,tx,ty,gx1,gy1,gx2,gy2);
        bfs();
    }
    return 0;
}

转载于:https://www.cnblogs.com/Rye-Catcher/p/9539386.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值