推箱子
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6767 Accepted Submission(s): 1908
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//hdu1254((bfs+dfs)||(bfs+bfs)) //题目大意:推箱子游戏,已知箱子和人的位置。求把箱子推到指定位置,至少要推多少下? //解题思路:这题整体还是用bfs搜索,以箱子为对象进行扩展。所不同的是,当箱子可以走到 //下一个位置时;这时需要判断人能否到达将箱子推到下一个位置的对应位置。这里用dfs||bfs判断能否到达 . //如果人不能到达,那肯定不能将其推到下一个位置。 //其次就是,由于推的过程中可能会走以前的道路,所以如果用二维数组标记的话就不能保证能否重复走 //由于人和箱子的位置在某个状态都是唯一的。如果用一个四维数组标记状态的话刚好可以消除这种故障。其分别标记箱子和人的位置。 //如下地图:当用二维数组时,就不能正确求解。 //1 1 1 1 1 1 //0 0 0 1 0 0 //0 0 2 4 0 3 #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; int map[10][10],vis[10][10][10][10],used[10][10]; int n,m,sx,sy,ex,ey,kx,ky,flag; int dx[4]={1,-1,0,0}; int dy[4]={0,0,-1,1}; struct node { int x,y,step; int sx,sy; friend bool operator<(node a,node b) { return a.step>b.step; } }; bool jude1(node s) { if(s.x<0||s.x>=n||s.y<0||s.y>=m) return false; if(map[s.x][s.y]==1||vis[s.x][s.y][s.sx][s.sy]==1) return false; return true; } void dfs(int x,int y,node t) { int fx,fy; if(t.x<0||t.y<0||t.x>=n||t.y>=m) return ; if(x==t.x&&y==t.y) //走到目标位置,返回真 { flag=1;return ; } for(int i=0;i<4;i++) { fx=x+dx[i]; fy=y+dy[i]; if(0<=fx&&fx<n&&fy>=0&&fy<m&&map[fx][fy]!=1&&!used[fx][fy]) { used[fx][fy]=1; if(fx==t.x&&fy==t.y) { flag=1;return ; } dfs(fx,fy,t); } } return; } void bfs() { priority_queue<node>q; memset(vis,0,sizeof(vis)); node p,s,t; p.x=sx,p.y=sy; p.sx=kx,p.sy=ky; p.step=0; vis[sx][sy][kx][ky]=1; q.push(p); while(!q.empty()) { p=q.top(); q.pop(); if(p.x==ex&&p.y==ey) //到达指定位置则打印步数。 { printf("%d\n",p.step); return ; } for(int i=0;i<4;i++) { s.x=p.x+dx[i]; s.y=p.y+dy[i]; //箱子的下一位置。 t.x=p.x-dx[i]; t.y=p.y-dy[i]; //人推箱子应处的位置 s.sx=t.x;s.sy=t.y; //更新人的位置 memset(used,0,sizeof(used)); used[p.x][p.y]=used[p.sx][p.sy]=1; flag=0; dfs(p.sx,p.sy,t); if(jude1(s)&&flag) //如果箱子不越界且人可以到达对应位置 { s.step=p.step+1; vis[s.x][s.y][s.sx][s.sy]=1; //标记状态 q.push(s); } } } printf("-1\n"); //否则,输出-1. return ; } int main() { int i,t,k,j; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(i=0;i<n;i++) { for(j=0;j<m;j++) { scanf("%d",&map[i][j]); if(map[i][j]==2) { sx=i,sy=j; //记录箱子的起点 } if(map[i][j]==4) { kx=i,ky=j; //人的起点 } if(map[i][j]==3) { ex=i,ey=j; //箱子的终点 } } } bfs(); } return 0; }