HDU 1254 推箱子 解題報告
阿新 • • 發佈:2019-01-31
Description
推箱子是一個很經典的遊戲.今天我們來玩一個簡單版本.在一個M*N的房間裡有一個箱子和一個搬運工,搬運工的工作就是把箱子推到指定的位置,注意,搬運工只能推箱子而不能拉箱子,因此如果箱子被推到一個角上(如圖2)那麼箱子就不能再被移動了,如果箱子被推到一面牆上,那麼箱子只能沿著牆移動.現在給定房間的結構,箱子的位置,搬運工的位置和箱子要被推去的位置,請你計算出搬運工至少要推動箱子多少格.
Input
輸入資料的第一行是一個整數T(1<=T<=20),代表測試資料的數量.然後是T組測試資料,每組測試資料的第一行是兩個正整數M,N(2<=M,N<=7),代表房間的大小,然後是一個M行N列的矩陣,代表房間的佈局,其中0代表空的地板,1代表牆,2代表箱子的起始位置,3代表箱子要被推去的位置,4代表搬運工的起始位置.Output
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
兩種搜尋結合的一道題目。題目要求箱子到終點要動幾次,顯然要用BFS;然而箱子的四個可能的移動方向並不一定是可行的,因為根據推箱子的遊戲規則,必須要有人在箱子一側推,才可使得箱子移動,因此需用DFS或BFS判斷人能否到達箱子的一側。個人認為在判斷人能否到達的時候,用DFS更好一些,因為並不需要求人到箱子的一側需要的最少步數。
本題要用兩個vis陣列。一個vis陣列對應箱子的移動,只需在每次執行一次樣例前memset即可,因為只要在一次樣例中,只要已經有方案到達過某格,之後到達該格的其他方案所需時間必定大於等於第一個方案到達該格的時間;另一個vis陣列需要在每次搜尋判斷人能否到達前,都memset一次,因為陣列不大,我當時就直接在子函式裡聲明瞭。
注意人不能出邊界,也不能踩在箱子上23333。箱子當然也不能出邊界。
#include<iostream> #include<stdio.h> #include<string.h> #include<queue> #include<stack> using namespace std; int t,m,n; int map[8][8]; int dir[4][2]={0,1,0,-1,-1,0,1,0}; struct Node { int manx,many,thx,thy; int num; }; int visited[8][8][4]; int bfs(struct Node o,int x,int y) { int vis[8][8]; memset(vis, 0, sizeof(vis)); queue<Node> st; st.push(o); while(!st.empty()) { struct Node no1,no2; no1=st.front(); st.pop(); if(no1.manx==x&&no1.many==y) { return 1; } for(int i=0;i<4;i++) { no2=no1; no2.manx+=dir[i][0]; no2.many+=dir[i][1]; if(no2.manx==no2.thx&&no2.many==no2.thy) continue; if(no2.manx<0||no2.manx>=m||no2.many<0||no2.many>=n) continue; if(vis[no2.manx][no2.many]) { //printf(" -1"); continue; } if(map[no2.manx][no2.many]==1) continue; vis[no2.manx][no2.many]=1; st.push(no2); } } return -1; } int main() { scanf("%d",&t); while(t--) { int ans=-1; scanf("%d%d",&m,&n); struct Node first; queue<Node> q; for(int i=0;i<m;i++) for(int j=0;j<n;j++) { scanf("%d",&map[i][j]); if(map[i][j]==2) { first.thx=i; first.thy=j; }else if (map[i][j]==4) { first.manx=i; first.many=j; } } first.num=0; memset(visited, 0, sizeof(visited)); q.push(first); while(!q.empty()) { struct Node order,next; order=q.front(); q.pop(); if(map[order.thx][order.thy]==3) { ans=order.num; break; } for(int i=0;i<4;i++) { next=order; next.manx=next.thx; next.many=next.thy; next.thx+=dir[i][0]; next.thy+=dir[i][1]; if(next.thx<0||next.thx>=m||next.thy<0||next.thy>=n) continue; if(visited[next.thx][next.thy][i]) continue; if(map[next.thx][next.thy]==1) continue; int x,y; x=next.manx-dir[i][0]; y=next.many-dir[i][1]; if(x<0||x>=m||y<0||y>=n) continue; int b=bfs(order,x,y); if(b== -1) continue; visited[next.thx][next.thy][i]=1; next.num++; q.push(next); } } printf("%d\n",ans); } return 0; }