推箱子(HDOJ 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 

My Code

#include 
#include 
#include 
using namespace std;

int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
int map[10][10];
int v[10][10][10][10];
int n, m, t;
struct node
{
    int x, y, bx, by;     //x和y是人的位置,bx和by是箱子的位置
    int step;             //step是箱子移动的步数
    friend bool operator<(node a, node b)
    {
        return a.step > b.step;
    }
} s;
bool check(node p)
{
    if (p.x < 0 || p.y < 0)
        return false;
    if (p.x >= n || p.y >= m)
        return false;
    if (map[p.x][p.y] == 1)
        return false;
    return true;
}
void bfs()
{
    memset(v, 0, sizeof(v));
    priority_queue q;
    node p, next;
    v[s.x][s.y][s.bx][s.by] = 1;
    s.step = 0;
    q.push(s);
    while (!q.empty())
    {
        p = q.top();
        q.pop();
        for (int i = 0; i < 4; i++)
        {
            next.x = p.x + dx[i];
            next.y = p.y + dy[i];
            if (check(next))
            {
                next.bx = p.bx;
                next.by = p.by;
                next.step = p.step;
                if (next.x == next.bx && next.y == next.by) //如果人下一步走在了箱子的位置上
                {                                           //那就是在推箱子
                    int tbx = next.bx + dx[i];              //箱子向人走的方向移动一格
                    int tby = next.by + dy[i];
                    if (tbx >= 0 && tbx < n && tby >= 0 && tby < m && map[tbx][tby] != 1)
                    {                                       //判断箱子能否移动
                        next.bx = tbx;
                        next.by = tby;
                        next.step++;
                    }
                }
                if (map[next.bx][next.by] == 3)
                {
                    cout << next.step << endl;
                    return;
                }
                if (!v[next.x][next.y][next.bx][next.by])   //标记重复状态
                {
                    v[next.x][next.y][next.bx][next.by] = 1;
                    q.push(next);
                }
            }
        }
    }
    cout << -1 << endl;
}
int main()
{
    cin >> t;
    while (t--)
    {
        cin >> n >> m;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
            {
                cin >> map[i][j];
                if (map[i][j] == 4)
                {
                    s.x = i;
                    s.y = j;
                }
                else if (map[i][j] == 2)
                {
                    s.bx = i;
                    s.by = j;
                }
            }
        bfs();
    }

    return 0;
}