1. 程式人生 > >【1254 HDU】推箱子

【1254 HDU】推箱子

題目:點選開啟題目連結

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;
    }
}