推箱子 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;
}