码迷,mamicode.com
首页 > 其他好文 > 详细

推箱子 HDU1254

时间:2019-01-24 14:37:39      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:lse   必须   close   图片   als   更新   spl   nmap   string   

较难的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 \n",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\n",u.x,u.y,u.d);
        if(u.x==ex&&u.y==ey){printf("%d\n",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\n");return ;

}
int main()
{
    int cas;scanf("%d",&cas);
    while(cas--)
    {
        scanf("%d%d",&n,&m);
       // printf("%d %d\n",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\n",sx,sy);
        bfs();


    }

    return 0;
}
View Code

 

 

 

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

 

技术分享图片
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<queue>
using namespace std;
int n,m;
int f[4][2]={0,1,1,0,0,-1,-1,0};
int vis[9][9][9][9];
int mat[9][9];
struct node{
    int x,y;//人坐标
    int bx,by;//箱子坐标 
    int temp;//推箱子步数
    bool friend operator<(const node &a, const node &b)
    {//必须优先队列,步数小优先 
        return a.temp>b.temp;
    }
}start;//起点 
void bfs()
{
    node s,t;
    priority_queue<node>q;
    memset(vis,0,sizeof(vis));
    vis[start.x][start.y][start.bx][start.by]=1;
    start.temp=0;
    q.push(start);
    while(!q.empty())
    {
        t=q.top();
        q.pop();
        if(mat[t.bx][t.by]==3)
        {//终点 
            printf("%d\n",t.temp);
            return;
        }
        for(int i=0;i<4;i++)
        {
            s.x=t.x+f[i][0];//人的下一步 
            s.y=t.y+f[i][1];
            if(s.y>=1&&s.x>=1&&s.y<=m&&s.x<=n&&mat[s.x][s.y]!=1)
            {
                s.bx=t.bx;//不能推时,箱子的坐标
                s.by=t.by;
                s.temp=t.temp;
                if(s.x==t.bx&&s.y==t.by)
                {//能推箱子 
                    int tbx=t.bx+f[i][0];
                    int tby=t.by+f[i][1];
                    if(tbx>=1&&tbx<=n&&tby>=1&&tby<=m&&mat[tbx][tby]!=1)
                    {//推完箱子判断是否过界,不过界,推数加1 
                        s.bx=tbx;//更新箱子坐标
                        s.by=tby;
                        s.temp++;
                    }
                }
                if(!vis[s.x][s.y][s.bx][s.by])
                {
                    vis[s.x][s.y][s.bx][s.by]=1;
                    q.push(s);
                }
            }
        }
    }
    printf("-1\n");
    return;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&mat[i][j]);
                if(mat[i][j]==4)
                {
                    start.x=i;start.y=j;
                    mat[i][j]=0;
                }
                if(mat[i][j]==2)
                {
                    start.bx=i;start.by=j;
                    mat[i][j]=0;
                }
            }
        }
        bfs();
    }
    return 0;
}
View Code

 

推箱子 HDU1254

标签:lse   必须   close   图片   als   更新   spl   nmap   string   

原文地址:https://www.cnblogs.com/bxd123/p/10314032.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!