zoukankan      html  css  js  c++  java
  • HDU 1254 推箱子(BFS加优先队列)

    传送门:

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

    推箱子

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 9942    Accepted Submission(s): 2920


    Problem Description
    推箱子是一个很经典的游戏.今天我们来玩一个简单版本.在一个M*N的房间里有一个箱子和一个搬运工,搬运工的工作就是把箱子推到指定的位置,注意,搬运工只能推箱子而不能拉箱子,因此如果箱子被推到一个角上(如图2)那么箱子就不能再被移动了,如果箱子被推到一面墙上,那么箱子只能沿着墙移动.

    现在给定房间的结构,箱子的位置,搬运工的位置和箱子要被推去的位置,请你计算出搬运工至少要推动箱子多少格.

     
    Input
    输入数据的第一行是一个整数T(1<=T<=20),代表测试数据的数量.然后是T组测试数据,每组测试数据的第一行是两个正整数M,N(2<=M,N<=7),代表房间的大小,然后是一个M行N列的矩阵,代表房间的布局,其中0代表空的地板,1代表墙,2代表箱子的起始位置,3代表箱子要被推去的位置,4代表搬运工的起始位置.
     
    Output
    对于每组测试数据,输出搬运工最少需要推动箱子多少格才能帮箱子推到指定位置,如果不能推到指定位置则输出-1.
     
    Sample Input
    1 5 5 0 3 0 0 0 1 0 1 4 0 0 0 1 0 0 1 0 2 0 0 0 0 0 0 0
     
    Sample Output
    4
     
    Author
    Ignatius.L & weigang Lee
     
    Recommend
    Ignatius.L   |   We have carefully selected several similar problems for you:  1253 1072 1240 1372 1429 
     
     
    分析:
    BFS加优先队列

    从人为起点开始bfs,如果人走的下一步是箱子所在的坐标,说明找到了箱子,

    箱子的坐标为当前所搜方向上人的坐标前进一格(就是推一格箱子,箱子前进的方向和人前进的方向是一致的),

    判断箱子是否到达了目的地,如果是则输出箱子移动的最少步数,到不了就输出-1。

    应该按照所走步数多少决定出队列顺序,所以用优先队列处理下。

    (人从起点找箱子是不计数的)

    需要注意的地方:

    1.要判断人的位置是不是合法:有没有越界或者该位置是墙

    2.要判断能不能推箱子:也就是人有没有找到箱子,比较一开始人和箱子是由距离的,

    如果人走的下一步是箱子所在的坐标,说明找到了箱子

    3.要判断箱子位置的合法性:越界或者该点是墙

    具有做法:

    先将箱子位置和人位置入队

    1.如果箱子到了指定位置,直接输出步数

    2.四个方向搜,先判断人的下一步位置是否合法,合法的话让人一直走,走到人能推箱子的时候

    ,在判断推导箱子之后箱子的位置合不合法,合法的话步数加1

    具体请参考代码:

    code:

    #include<bits/stdc++.h>
    using namespace std;
    int dir[4][2]= {0,1,1,0,0,-1,-1,0}; //方向数组
    #define max_v 12
    int n,m;
    int G[max_v][max_v];//存图
    int vis[max_v][max_v][max_v][max_v];
    struct node
    {
        int x,y;//人的坐标
        int bx,by;//箱子的坐标
        int step;//推箱子的步数
        bool friend operator<(const node &a, const node &b)
        {
            //必须优先队列,步数小优先ye1js
            return a.step>b.step;
        }
    
    } start; //起点
    bool check_person(node next)//判断人的位置是否合法
    {
        if(next.x>=1&&next.x<=n&&next.y>=1&&next.y<=m&&G[next.x][next.y]!=1)//没有越界且不是墙
            return true;
        else
            return false;
    }
    bool check_box1(node next,node t)//判断能不能推箱子
    {
        if(next.x==t.bx&&next.y==t.by)//如果人走的下一步是箱子所在的坐标,说明找到了箱子
            return true;
        else
            return false;
    }
    int check_box2(int tbx,int tby)//判断箱子坐标的合法性
    {
        if(tbx>=1&&tbx<=n&&tby>=1&&tby<=m&&G[tbx][tby]!=1)//越界或者墙
            return true;
        else
            return false;
    }
    void bfs()
    {
        node next,t;
        priority_queue<node>q;
        memset(vis,0,sizeof(vis));//标志位置空
        //队列初始化
        vis[start.x][start.y][start.bx][start.by]=1;
        start.step=0;
        q.push(start);
    
        while(!q.empty())
        {
            t=q.top();
            q.pop();
            if(G[t.bx][t.by]==3)//箱子到了指定位置
            {
                cout<<t.step<<endl;
                return ;
            }
    
            for(int i=0; i<4; i++)
            {
                next.x=t.x+dir[i][0];//人的下一步
                next.y=t.y+dir[i][1];
    
    
                if(check_person(next))//判断人的下一步位置是否合法
                {
                    next.bx=t.bx;//不能推箱子时,箱子的坐标
                    next.by=t.by;
                    next.step=t.step;
    
    
                    if(check_box1(next,t))//能推箱子
                    {
                        int tbx=t.bx+dir[i][0];//推动箱子之后,箱子的坐标
                        int tby=t.by+dir[i][1];
    
    
                        if(check_box2(tbx,tby))//判断推导箱子之后箱子坐标的合法性,合法则更新坐标
                        {
                            next.bx=tbx;
                            next.by=tby;
                            next.step++;//步数加1
                        }
                    }
                    if(vis[next.x][next.y][next.bx][next.by]==0)//该情况没有搜过,则入队,开始搜
                    {
                        vis[next.x][next.y][next.bx][next.by]=1;
                        q.push(next);
                    }
                }
            }
        }
        cout<<"-1"<<endl;
        return ;
    }
    int main()
    {
        int t;
        cin>>t;
        while(t--)
        {
            cin>>n>>m;
            for(int i=1; i<=n; i++)
            {
                for(int j=1; j<=m; j++)
                {
                    cin>>G[i][j];
                    if(G[i][j]==4)
                    {
                        start.x=i;//找到人在坐标
                        start.y=j;
                        G[i][j]=0;
                    }
                    if(G[i][j]==2)
                    {
                        start.bx=i;//找到箱子的坐标
                        start.by=j;
                        G[i][j]=0;
                    }
                }
            }
            bfs();
        }
        return 0;
    }
  • 相关阅读:
    1082 射击比赛 (20 分)
    1091 N-自守数 (15 分)
    1064 朋友数 (20 分)
    1031 查验身份证 (15 分)
    1028 人口普查 (20 分)
    1059 C语言竞赛 (20 分)
    1083 是否存在相等的差 (20 分)
    1077 互评成绩计算 (20 分)
    792. 高精度减法
    791. 高精度加法
  • 原文地址:https://www.cnblogs.com/yinbiao/p/9350249.html
Copyright © 2011-2022 走看看