推箱子
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6758 Accepted Submission(s): 1906
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
感觉还是有难度的,刚开始的时候没考虑人所在的位置,这里有一个坑,箱子移动的时候人必须在箱子后边,这样才可以推到箱子,这样的话就会有点复杂,每次推箱子的时候我们都应该判断一下,上一次人所在的位置是否可以到达这次推箱子的位置,所以这就不只是一个bfs可以搞定的了,在结构体中我们记录的应该有箱子和人的位置以及当前步数,每一次位置变换都应该更新人还有箱子的位置,同时判定该方案的可行性(加上了注释就CE了,不知道是什么鬼)
#include<stdio.h> #include<cstring> #include<queue> #include<iostream> #include<algorithm> using namespace std; int dx[4]={0,0,1,-1}; int dy[4]={1,-1,0,0}; int map[10][10],mark[10][10][10][10]; int n,m,flag,markk[10][10]; int xiangx,xiangy; struct dian { int x,y; int renx,reny; int step; }st,end; struct ren { int x,y; }vv,stt; int bffs(ren stt) { queue<ren>q; markk[stt.x][stt.y]=1; q.push(stt); ren v,vn; while(!q.empty()) { vn=q.front(); q.pop(); if(vn.x==vv.x&&vn.y==vv.y) return 1;//可以到达现在推箱子的位置 for(int i=0;i<4;i++) { v.x=vn.x+dx[i]; v.y=vn.y+dy[i]; if(v.x>=n||v.x<0||v.y>=m||v.y<0) continue;//不能出界 if(map[v.x][v.y]==1) continue; if(v.x==xiangx&&v.y==xiangy) continue; //不能在以前箱子所在的位置 if(markk[v.x][v.y]) continue; markk[v.x][v.y]=1; q.push(v); } } return 0; } void bfs(dian st) { queue<dian>p; p.push(st);//使用人还有箱子的位置实现四维标记 mark[st.x][st.y][st.renx][st.reny]=1; dian v,vn; while(!p.empty()) { vn=p.front(); p.pop(); if(vn.x==end.x&&vn.y==end.y) {//如果现在箱子被推到了指定的位置 flag=1; printf("%d ",vn.step); return; } for(int i=0;i<4;i++) {//箱子位置变更 v.x=vn.x+dx[i]; v.y=vn.y+dy[i]; v.step=vn.step+1; v.renx=vn.x; v.reny=vn.y; vv.x=vn.x-dx[i];//vv中的x,y存储了推箱子时人应该在的位置 vv.y=vn.y-dy[i]; if(v.x>=n||v.x<0||v.y>=m||v.y<0) continue; if(map[v.x][v.y]==1) continue; if(map[vv.x][vv.y]==1||vv.x>=n||vv.x<0||vv.y>=m||vv.y<0) continue; if(mark[v.x][v.y][v.renx][v.reny]) continue; stt.x=vn.renx;//结构体中存放的有当时人的位置 stt.y=vn.reny; xiangx=vn.x; xiangy=vn.y; memset(markk,0,sizeof(markk)); if(!bffs(stt)) continue;//箱子被推之前的位置,因为还要判定是否可以推 mark[v.x][v.y][v.renx][v.reny]=1; p.push(v); } } } int main() { int T; scanf("%d",&T); while(T--) { flag=0; scanf("%d%d",&n,&m); for(int i=0;i<n;i++) for(int j=0;j<m;j++) { scanf("%d",&map[i][j]); if(map[i][j]==2) { st.x=i; st.y=j; xiangx=i; xiangy=j; } if(map[i][j]==3) { end.x=i; end.y=j; } if(map[i][j]==4) { st.renx=i; st.reny=j; } } st.step=0; memset(mark,0,sizeof(mark)); memset(markk,0,sizeof(markk)); bfs(st); if(!flag) printf("-1 "); } return 0; }