推箱子
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6416 Accepted Submission(s):
1834
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
Author
Ignatius.L & weigang Lee
Recommend
最开始写这道题的时候,想得很简单,如果箱子可以移动,那么移动的方向上箱子的前一点必须为空地,然后我想成了只要箱子移动的前一个点事空地箱子就可以朝这个方向移动。。。于是我写完了代码,过掉了超水的测试数据,然后华丽wa。。。仔细想了想,原来我没有考虑人的能不能走过来。。。。
咳咳,改变思想,重新出发,完全理解题意后,感觉有点复杂,不禁一阵头大,准备在网上搜个代码参考一下,了解了用四维数组标记的方法,顿时有了想法,完成了自己的代码。代码中定量很多,必须要细心。
先广搜箱子可以去的位置,然后深搜人是否能达到推箱子的这个点,记得将箱子的位置开成墙。
题意:中文题,很好理解。
附上代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 using namespace std; 6 struct node 7 { 8 int x,y; //箱子的位置 9 int xx,xy; //人的位置 10 int t; //箱子动的格数 11 } s1,s2; 12 int f[4][2]= {0,1,0,-1,1,0,-1,0}; //方向变量 13 int map[10][10]; //记录地图 14 int vis[10][10][10][10]; //四维数组标记,同时记录箱子的位置和人的位置,去除重复的 15 int n,m; //边界 16 int a1,a2,b1,b2; //初始值 17 int flag[10][10],kk; 18 19 bool xx(int a,int b) 20 { 21 if(a>=0&&a<n&&b>=0&&b<m&&map[a][b]!=1) return true; 22 return false; 23 } 24 25 void DFS(int nx,int ny,int mx,int my) 26 { 27 if(nx==mx&&ny==my) //如果从要到的点能搜到此时人的位置,则人可以走过来 28 { 29 kk=1; //若能走来,标记为1 30 return; 31 } 32 for(int i=0; i<4&&!kk; i++) 33 { 34 int x=nx+f[i][0]; 35 int y=ny+f[i][1]; 36 if(xx(x,y)&&!flag[x][y]) 37 { 38 flag[x][y]=1; //走过的点标记为1 39 DFS(x,y,mx,my); //继续搜索 40 } 41 } 42 } 43 44 void BFS() 45 { 46 queue<node> q; 47 while(!q.empty()) 48 q.pop(); 49 int nx,ny; 50 s1.x=a1; //初始化 51 s1.y=b1; 52 s1.xx=a2; 53 s1.xy=b2; 54 s1.t=0; 55 vis[a1][b1][a2][b2]=1; //开始状态标记为已出现 56 q.push(s1); 57 while(!q.empty()) 58 { 59 s1=q.front(); 60 q.pop(); 61 if(map[s1.x][s1.y]==3) //箱子到达指定位置后,队列循环结束 62 { 63 printf("%d ",s1.t); 64 return; 65 } 66 for(int i=0; i<4; i++) 67 { 68 s2.x=s1.x+f[i][0]; //箱子移动后的位置 69 s2.y=s1.y+f[i][1]; 70 nx=s1.x-f[i][0]; //如果箱子能移动到那个位置,人必须能走到这个点 71 ny=s1.y-f[i][1]; 72 if(xx(s2.x,s2.y)&&xx(nx,ny)&&!vis[s2.x][s2.y][nx][ny]) 73 //xx()函数判断是否超边界和是否是墙,箱子移动后的位置和人要到的位置都必须满足,并且此时这个状态是没有出现过的 74 { 75 memset(flag,0,sizeof(flag)); //地图中所有不是墙的点都能走 76 flag[nx][ny]=flag[s1.x][s1.y]=1; //箱子移动前的位置和人要到的位置都看做墙 77 kk=0; //标记人是否能走过来 78 DFS(nx,ny,s1.xx,s1.xy); //深搜查询 79 if(kk) //如果人能走到 80 { 81 vis[s2.x][s2.y][nx][ny]=1; //这个状态标记已出现 82 s2.xx=nx; //记录此时人到的位置 83 s2.xy=ny; 84 s2.t=s1.t+1; //步数加一 85 q.push(s2); //入队列 86 } 87 } 88 } 89 } 90 printf("-1 "); //如果不能到,则输出-1 91 return; 92 } 93 int main() 94 { 95 int T,i,j; 96 scanf("%d",&T); 97 while(T--) 98 { 99 scanf("%d%d",&n,&m); 100 memset(vis,0,sizeof(vis)); //标记全部初始化为0 101 for(i=0; i<n; i++) 102 for(j=0; j<m; j++) 103 { 104 scanf("%d",&map[i][j]); 105 if(map[i][j]==2) //记录箱子的起始位置 106 { 107 a1=i; 108 b1=j; 109 } 110 if(map[i][j]==4) //记录人的起始位置 111 { 112 a2=i; 113 b2=j; 114 } 115 } 116 BFS(); 117 } 118 return 0; 119 }