|
推箱子Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 9850 Accepted Submission(s): 2894
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
|
题意:推箱子....大家应该都知道怎么个意思,就是箱子到目的地就可以了。
思路:先用BFS计算箱子到目的地的最短的距离,然后用DFS算出人能不能到箱子之前的状态(这里也可以用BFS计算,数据比较小,才7),因为要这样才可以推动箱子
如果人到不了,那么就continue;掉,因为走不过去
一开始我们要用一个数组来储存人和箱子的坐标,因为人和箱子可以重复走一条路,如果坐标都重复的话说明已经走过了之前的路,就不用再走了
代码:
#include <iostream> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int maxn=10; int map[maxn][maxn]; int n,m,dir[4][2]={0,1,0,-1,1,0,-1,0}; int bx,by,px,py,flag; bool vis[maxn][maxn][maxn][maxn],dfs_vis[maxn][maxn]; //这里四维数组储存箱子和人所在的坐标 struct node { int bx,by; int px,py,t; }; bool judge(int x,int y) //判断能不能走 { if (x<=0||x>m||y<=0||y>n||map[x][y]==1) return true; return false; } void dfs(int x,int y,int nx,int ny) //判断人能不能到箱子之前的坐标 nx,ny表示终点 { int i; if (flag==1) return ; if (x==nx&&y==ny) { flag=1; return ; } for (i=0;i<4;i++) if (judge(x+dir[i][0],y+dir[i][1])==true||dfs_vis[x+dir[i][0]][y+dir[i][1]]==true) continue; else { dfs_vis[x+dir[i][0]][y+dir[i][1]]=true; //这里是一个坑点,一开始我按照普通的dfs写,然后....wa了 dfs(x+dir[i][0],y+dir[i][1],nx,ny); //其实走过的路直接标记就可以了,不用恢复,不然会超时的 } return ; } int bfs(int x,int y) { int i; node now,end; now.bx=x;now.by=y; now.px=px;now.py=py;now.t=0; memset(vis,false,sizeof(vis)); vis[x][y][px][py]=true; queue<node> q; while (!q.empty()) q.pop(); q.push(now); while (!q.empty()) { now=q.front(); q.pop(); for (i=0;i<4;i++) { end.bx=now.bx+dir[i][0]; end.by=now.by+dir[i][1]; if (judge(end.bx,end.by)==true) //判断箱子能不能走 continue; if (vis[end.bx][end.by][now.bx][now.by]==true) continue; memset(dfs_vis,false,sizeof(dfs_vis)); dfs_vis[now.bx][now.by]=true;flag=0; //这里标记是因为 人推箱子,箱子之前的坐标不能去 dfs(now.px,now.py,now.bx-dir[i][0],now.by-dir[i][1]); //初始地方 if (flag==0) continue; end.px=now.bx; end.py=now.by; end.t=now.t+1; vis[end.bx][end.by][end.px][end.py]=true; if (map[end.bx][end.by]==3) return end.t; q.push(end); } } return -1; } int main() { int t,i,j,ans; cin>>t; while (t--) { cin>>m>>n; for (i=1;i<=m;i++) for (j=1;j<=n;j++) { cin>>map[i][j]; if (map[i][j]==2) { bx=i;by=j; } if (map[i][j]==4) { px=i;py=j; } } ans=bfs(bx,by); cout<<ans<<endl; } return 0; }