题目:点击打开题目链接

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

题目思路:要求箱子到达目的地最少移动的格数,而这道题是人推着箱子走的,所以除了考虑箱子的位置是否合理(判断是否超出房间以外而且箱子的位置不能是墙)之外,还要考虑人能否把箱子推到下一个位置,即考虑人是否能到达箱子的屁股后面(因为要想把箱子往前推一格,人必须在箱子的后面一格才能推箱子)这2个因素。因此,除了用一个bfs把箱子移动的格数求出来之外,还需要用一个bfs或dfs来判断人是否能到达箱子的屁股后面。还有就是这道题要注意箱子走过的地方还可以回来。

如果还是有点不明白的话可以看看下面的图。

假设起初箱子在X(蓝色)的位置,人在Y(蓝色)的位置,为了方便,我们就假设房间里没有墙,都可以走。

1.假设箱子的下一个位置是b的位置,那么人要想把箱子推到b的位置,人就得在P的位置才能把箱子推到b处,所以这个时候我们就要判断人是否能从Y的位置走到P的位置,而且在这个过程中,人不能穿过箱子的位置X走到P,即人不仅不能撞到墙,也不能撞到箱子

2.因为这只走了4个方向中的一个方向,下面我们在判断箱子往右走的情况,同样也是除了判断箱子的下一个位置是否合理外,还要判断人是否能从Y走到P的位置,如图

然后就这样以此类推,直到箱子走到目的地,不能到达就输出-1.

My  DaiMa:

#include <iostream>
#include<stdio.h>
#include<malloc.h>
#include<queue>
#include<algorithm>
#include<string.h>
using namespace std;
int n,m,flag[10][10];///n行m列,flag存的是房间里的数字
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
int vis[10][10][10][10];
int mark[10][10];
struct position
{
    int bx,by,px,py,step;
}start;
bool judge(int cur_px,int cur_py,int nex_px,int nex_py,int cur_bx,int cur_by)
{
    memset(mark,0,sizeof(mark));///人走过的地方以免重复,就不判断了,所以用到标记
    queue <position> q;
    position cur,nex;
    cur.px = cur_px;
    cur.py = cur_py;
    mark[cur.px][cur.py] = 1;
    q.push(cur);
    while(!q.empty())
    {
        cur = q.front();
        q.pop();
        if(cur.px == nex_px && cur.py == nex_py) return true;
        for(int i = 0; i < 4; i++)
        {
            nex.px = cur.px + dir[i][0];
            nex.py = cur.py + dir[i][1];
            if(nex.px == cur_bx && nex.py == cur_by) continue;///人的下一个位置不能是箱子的位置,因为人不能穿过箱子
            if((nex.px >= 0 && nex.px < n) && (nex.py >=0 && nex.py < m) && flag[nex.px][nex.py] != 1  && mark[nex.px][nex.py] != 1)
            {
                mark[nex.px][nex.py] = 1;
                q.push(nex);
            }
        }
    }
    return false;
}
int bfs()
{
    memset(vis,0,sizeof(vis));
    start.step = 0;
    vis[start.bx][start.by][start.px][start.py] = 1;
    queue<position>Q;
    Q.push(start);
    position cur,nex;
    while(!Q.empty())
    {
        cur = Q.front();
        Q.pop();
        if(flag[cur.bx][cur.by] == 3) return cur.step;
        for(int i = 0; i < 4; i++)
        {
            nex.bx = cur.bx + dir[i][0];///人把箱子往前推一步,即箱子的下一个位置
            nex.by = cur.by + dir[i][1];
            nex.px = cur.bx - dir[i][0];///人要想把箱子往前推一步,那人就得在箱子的屁股后面
            nex.py = cur.by - dir[i][1];

            if(nex.px < 0 || nex.px >= n || nex.py < 0 || nex.py >= m || flag[nex.px][nex.py] == 1) continue;///判断人的位置是否合理
            if(nex.bx < 0 || nex.bx >= n || nex.by < 0 || nex.by >= m || flag[nex.bx][nex.by] == 1 || vis[nex.bx][nex.by][nex.px][nex.py] == 1) continue;///判断箱子的位置是否合理
            if(judge(cur.px,cur.py,nex.px,nex.py,cur.bx,cur.by))///判断人是否能到达箱子的后面
            {
                nex.step = cur.step + 1;
                vis[nex.bx][nex.by][nex.px][nex.py] = 1;
                Q.push(nex);
            }
        }
    }
    return -1;
}
int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < m; j++)
            {
                cin >> flag[i][j];
                if(flag[i][j] == 2)
                {
                    start.bx = i;
                    start.by = j;
                }
                if(flag[i][j] == 4)
                {
                    start.px = i;
                    start.py = j;
                }
            }
        }
        int ans;
        ans = bfs();
        cout << ans << endl;
    }
}