HDU 1254 推箱子(广搜+优先队列)

本文介绍了一种经典的推箱子游戏的简化版,并提供了一个算法解决方案。该算法利用优先队列来寻找将箱子从起始位置推到目标位置所需的最少步数。

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

#include <iostream>
#include <queue>
#include <memory.h>
using namespace std;
struct status
{
    int bx,by;//箱子的坐标
    int px,py;//人的坐标
    int step;
    bool friend operator <(const status& a,const status& b)//重载优先队列的比较符
    {
        return a.step>b.step;
    }
};
int main()
{
    int T,m,n;
    int mmap[10][10];
    int di[4][2]= {-1,0,1,0,0,-1,0,1};
    bool visit_of_person[10][10][10][10];
    priority_queue <status> q;
    //使用优先队列可以使推动箱子次数多的状态推迟出队,从而保证箱子每个能推动的方向都被访问到并推动
   //若直接使用队列,则无法使每种情况都走到
    cin>>T;
    for(int Ti=0; Ti<T; ++Ti)
    {
        memset(visit_of_person,false,10000);
        status start;
        start.step=0;
        int endx,endy;
        int ans=0;
        cin>>m>>n;
        for(int i=0; i<m; ++i)
            for(int j=0; j<n; ++j)
            {
                cin>>mmap[i][j];
                if(mmap[i][j]==2)
                    start.bx=i,start.by=j;
                else if(mmap[i][j]==3)
                    endx=i,endy=j;
                else if(mmap[i][j]==4)
                    start.px=i,start.py=j;
            }
        q.push(start);
        bool found=false;
        while(!q.empty()&&!found)
        {
            for(int i=0; i<4; ++i)
            {
                status cur_status=q.top();
                cur_status.px+=di[i][0];
                cur_status.py+=di[i][1];
                //先判越界,否则可能出现数组下标为负的情况
                if(cur_status.px<0||cur_status.px>=m||cur_status.py<0||cur_status.py>=n)//越界
                    continue;
                if(mmap[cur_status.px][cur_status.py]==1)//走到墙上
                    continue;
                if(visit_of_person[cur_status.bx][cur_status.by][cur_status.px][cur_status.py])//该状态已经走过
                    continue;
                if(cur_status.px==cur_status.bx&&cur_status.py==cur_status.by)//走到箱子上
                {
                    int next_box_x=cur_status.bx+di[i][0];
                    int next_box_y=cur_status.by+di[i][1];
                    if(next_box_x<0||next_box_x>=m||next_box_y<0||next_box_y>=n)//箱子越界
                        continue;
                    if(mmap[next_box_x][next_box_y]==1)//箱子走到墙上
                        continue;
                    //箱子既没走到墙上也没越界,则箱子走一步
                    cur_status.bx=next_box_x;
                    cur_status.by=next_box_y;
                    ++cur_status.step;
                    if(cur_status.bx==endx&&cur_status.by==endy)//箱子走到终点
                    {
                        found=true;
                        ans=cur_status.step;
                    }
                }
                q.push(cur_status);
                visit_of_person[cur_status.bx][cur_status.by][cur_status.px][cur_status.py]=true;
            }
            q.pop();
        }
        if(found)
            cout<<ans<<endl;
        else
            cout<<-1<<endl;
        while(!q.empty())//清空队列
            q.pop();
    }
    return 0;
}

个人网站:https://jqh.zone 阅读原文

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值