题解: HDU 1254 :推箱子 (BFS)

上题目

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

分析

人能推动箱子的几个要素

1.人的下一个位置是箱子现在的位置

2.箱子移动的方向是人推箱子时移动的方向

  1. 人和箱子说组成的四维坐标是用来判断是否经历的依据

上代码 + 注释

#include<stdio.h> 
#include<queue> 
#include<algorithm> 

using namespace std;

struct Node
{
    int x, y;
    int bx, by;
    int num;
    bool friend operator < (const Node &a, const Node &b)
    {
        return a.num > b.num;
    }//优先队列 
} star;

int map[9][9];
bool mark[9][9][9][9];//用人跟箱子的位置标记状态 
int dis[4][2] = { 1, 0, 0, -1, -1, 0, 0, 1 };
int n, m, ans;


void input()// 输入函数
{
    int i, j;
    for (i = 0; i < n; i++)
    {
        for (j = 0; j < m; j++)
        {
            scanf("%d", &map[i][j]);
            if (map[i][j] == 4)
            {
                star.x = i;
                star.y = j;
                map[i][j] = 0;
            }
            if (map[i][j] == 2)
            {
                star.bx = i;
                star.by = j;
                map[i][j] = 0;
            }
        }
    }
}
//输入地图,找到人跟位置的点。 

int BFS()
{
    int i, x, y, num, xx, yy;
    Node now, next;
    priority_queue<Node> Q;

    Q.push(star);

    mark[star.x][star.y][star.bx][star.by] = true;

    while (!Q.empty())
    {
        now = Q.top();
        Q.pop();

        if (map[now.bx][now.by] == 3)
            return now.num;//如果箱子到终点退出搜索 

        for (i = 0; i < 4; i++)//四个方向循环
        {
            x = now.x + dis[i][0];
            y = now.y + dis[i][1];


            if (x < 0 || x >= n || y < 0 || y >= m)//越界 继续
                continue;

            if (map[x][y] == 1) //墙 继续
                continue;

            next.bx = now.bx;
            next.by = now.by;
            next.num = now.num;  //注意题目要求统计的是箱子的移动个数
            next.x = x;
            next.y = y;


            if (x == now.bx && y == now.by)//如果下个点是箱子的位置 
            {
                xx = x + dis[i][0];
                yy = y + dis[i][1];

                if (xx < 0 || xx >= n || yy < 0 || yy >= m)
                    continue;

                if (map[xx][yy] == 1)
                    continue;

                next.bx = xx;
                next.by = yy;
                next.num++;
            }


            if (mark[x][y][next.bx][next.by])//如果推完后的状态已经经历过就不推了 
                continue;

            mark[x][y][next.bx][next.by] = true;
            Q.push(next);
        }
    }
    return -1;
}


int main()
{
    int T, ans;
    scanf("%d", &T);
    while (T--)
    {
        memset(mark, 0, sizeof(mark));//最重要的初始话忘记了,wa了几次 
        scanf("%d%d", &n, &m);

        input();

        star.num = 0;

        ans = BFS();
        printf("%d\n", ans);
    }
    return 0;
}
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值