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