zoukankan      html  css  js  c++  java
  • 推箱子 HDU1254 (bfs)

    较难的bfs

    有两种方法做

    一种双重bfs:

    主bfs是箱子   还要通过dfs判断人是否能到箱子后面 

    用inmap函数的好处。。

    箱子要用三位数组来标记  因为箱子可以回到原来到过的地方  因为推的方向不同 (第三位来表示方向)

    并且地图无需改变(一些人在结构体里自带一份地图)  

    这题箱子的位置 对人来是是墙 不可越过  用设置vis2来实现  非常巧妙  

    用全局flag来代替dfs中的bool 方便很多 也不容易出错

    #include<bits/stdc++.h>
    using namespace std;
    
    int n,m,m1[10][10],vis[10][10][4],vis2[10][10];
    int sx,sy,ex,ey,rx1,ry1;
     int dx[4]={0,1,0,-1};
    int  dy[4]={1,0,-1,0};
    int flag=0;
    
    struct node
    {
        int x,y,d,rx,ry;
        node(int x=0,int y=0,int d=0,int rx=0,int ry=0):x(x),y(y),d(d),rx(rx),ry(ry){}
    };
    
    
    bool inmap(int a,int b)
    {
        if(a<1||a>n||b<1||b>m||m1[a][b]==1)
            return false;
        return true;
    
    }
    
    void bfs1( int sx, int sy,int ex,int ey)
    {
    
        if(sx==ex&&sy==ey) {flag=1;return ;}
        if(flag==1)return;//值得学习
        for(int i=0;i<4;i++)
        {
    
            if(vis2[sx+dx[i]][sy+dy[i]]==0&&inmap(sx+dx[i],sy+dy[i]))
            {
                //printf("%d %d 
    ",sx+dx[i],sy+dy[i]);
                vis2[sx+dx[i]][sy+dy[i]]=1;
                bfs1(sx+dx[i],sy+dy[i],ex,ey);
    
            }
    
        }
    
    }
    
    
    void bfs()
    {
    
        memset(vis,0,sizeof(vis));
        memset(vis2,0,sizeof(vis2));
        node u(sx,sy,0,rx1,ry1);
        queue<node>q;
        q.push(u);
    
        while(!q.empty())
        {
    
            u=q.front();q.pop();
           // printf("%d %d %d
    ",u.x,u.y,u.d);
            if(u.x==ex&&u.y==ey){printf("%d
    ",u.d);return;}
    
            for(int i=0;i<4;i++)
            {
                node v(u.x+dx[i],u.y+dy[i],u.d+1,u.rx,u.ry);//用自加是错的
    
               if(inmap(u.x-dx[i],u.y-dy[i])&&inmap(v.x,v.y)&&vis[v.x][v.y][i]==0)
                {
                      flag=0;
                     memset(vis2,0,sizeof(vis2));
                     vis2[u.rx][u.ry]=1;
                     vis2[u.x][u.y]=1;//非常关键!!!箱子也是障碍!!!
                     bfs1(u.rx,u.ry,u.x-dx[i],u.y-dy[i]);
    
                    if(flag)
                      {
                        vis[v.x][v.y][i]=1;
                          v.rx=u.x-dx[i];
                          v.ry=u.y-dy[i];
                           q.push(v);
                      }
                }
            }
        }
           printf("-1
    ");return ;
    
    }
    int main()
    {
        int cas;scanf("%d",&cas);
        while(cas--)
        {
            scanf("%d%d",&n,&m);
           // printf("%d %d
    ",n,m);
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
            {
                scanf("%d",&m1[i][j]);
                if(m1[i][j]==3){ex=i;ey=j;}
                if(m1[i][j]==2){sx=i;sy=j;}
                if(m1[i][j]==4){rx1=i;ry1=j;}
    
            }
           // printf("%d %d
    ",sx,sy);
            bfs();
    
    
        }
    
        return 0;
    }
    View Code

    还有一种方法是一次BFS  优先队列   用四维数组来标记人和箱子的座标 然后人疯狂乱走   如果人走到了箱子上了  就相当于推动了一次

    回顾:

    一定要用优先队列   不然的话是以人走的步数为基准    

    还有一定要注意  队列里面的优先级是反的!!!!

    #include<iostream>
    #include<queue>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define N 9
    #define inf 0x3f3f3f3f
    
    int dx[4]={0,0,1,-1};
    int dy[4]={1,-1,0,0};
    int sx,sy,ex,ey,rx,ry;
    int n,m;
    int mp[N][N];
    
    
    bool inmap(int x,int y)
    {
        return x>=1&&x<=n&&y>=1&&y<=m;
    }
    
    struct node
    {
        int x,y,d,rx,ry;
        bool operator <(const node &h)const{
          return d>h.d;
        }
    };
    
    int vis[N][N][N][N];
    
    void bfs()
    {
        memset(vis,0,sizeof vis);
        node u,v;
        u.x=sx;
        u.y=sy;
        u.d=0;
        u.rx=rx;
        u.ry=ry;
        priority_queue<node>q;
        q.push(u);
        vis[sx][sy][rx][ry]=1;
        while(!q.empty())
        {
            u=q.top();q.pop();
          
            if( mp[u.x][u.y]==3 ){printf("%d
    ",u.d);return ;}
    
            for(int i=0;i<4;i++)
            {
                v=u;
                v.rx+=dx[i];
                v.ry+=dy[i];
                if(  inmap(v.rx,v.ry)  &&mp[v.rx][v.ry]!=1)
                {
                    if(v.rx==v.x&&v.ry==v.y&& inmap(v.x+dx[i],v.y+dy[i] )&&mp[v.x+dx[i]][v.y+dy[i]]!=1   )
                    {
                        v.x+=dx[i];
                        v.y+=dy[i];
                        v.d+=1;
                    }
                    if(!vis[v.x][v.y][v.rx][v.ry] )
                        {
                        q.push(v);
                        vis[v.x][v.y][v.rx][v.ry]=1;
                        }
                }
            }
        }
        printf("-1
    ");
    }
    
    
    
    int main()
    {
        int cas;cin>>cas;
        while(cas--)
        {
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                  {
                    scanf("%d",&mp[i][j]);
                    int t=mp[i][j];
                    if(t==4){rx=i;ry=j;}
                    if(t==2){sx=i;sy=j;}
                  }
            bfs();
        }
     return 0;
    }
  • 相关阅读:
    牛客练习赛19 D-托米去购物
    牛客练习赛19 托米的简单表示法
    Codeforces Round #492 (Div. 2) [Thanks, uDebug!]
    Codeforces Round #393 (Div. 2) (8VC Venture Cup 2017
    Codeforces Round #393 (Div. 2) (8VC Venture Cup 2017
    Codeforces Round #491 (Div. 2) E
    I00018 生成全1数
    I00017 生成9开头的按位递减数
    I00017 生成9开头的按位递减数
    HDU1042 n!
  • 原文地址:https://www.cnblogs.com/bxd123/p/10314032.html
Copyright © 2011-2022 走看看