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
对于当前箱子(bx,by)若想将箱子移至(bx+1,by)
则人必须先能够走到(bx-1,by), ——一次bfs
然后箱子能够被推到(bx+1,by)。
(当然下面代码中先判断了箱子能不能被推再判断人是否能到,这个顺序无碍结果如何)
【变量常量设计思路】
基本变量、常量 | 剪枝变量 |
---|---|
地图-graph[x][y] | visit[x][y]、hush[x][y] |
地图尺寸n、m | |
移动方向常量directp[4][2] | |
结构体struct node |
其中,对于存储每一步移动信息的结构体node来说,结合地图信息可以得知,每一步真正在改变的是箱子的位置和人的位置,所以真正需要时时刻刻存储更新的是这箱子的坐标(x,y)和人的坐标(px,py),以及所求时间time。(ps:将判断是否越界的函数放在结构体里面是因为每一个判断的结构体都需要进行越界判断,有种结构体和函数绑定的感觉)
另外,visit[][]是对人移动bfs时的剪枝、hush[][]是对箱子移动bfs时的剪枝
AC代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#define len (int)strlen(word)
#define max(a,b) (a)>(b)>(a):(b)
#define min(a,b) (a)<(b)>(a):(b)
using namespace std;
int n,m;
int graph[10][10],hush[10][10][4],visit[10][10]; //hush用于对箱子的剪枝,visit用于对人的剪枝
int direct[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
struct node{
int x,y; //储存箱子的位置(需要检验->是否越界(check1())+是否能走)
int px,py; //储存可以实现时人的位置(需要检验->人能否从前一个状态到当前所需状态+是否越界(check2())+是否能走)
int time;
bool check1(){
if(x>=1&&x<=n&&y>=1&&y<=m)
return true;
return false;
}
bool check2(){
if(px>=1&&px<=n&&py>=1&&py<=m)
return true;
return false;
}
};
struct node s;
bool bfs_per(struct node per1,struct node per2){ //搜索人能否从前一个状态(per1)到当前所需状态(per2)
memset(visit,0,sizeof(visit));
queue<struct node>que;
que.push(per1);
visit[per1.px][per1.py]=1;
while(!que.empty()){
struct node p1=que.front();
que.pop();
if(p1.px==per2.px&&p1.py==per2.py){
return true;
}
for(int i=0;i<4;i++){
struct node p2;
p2.px=p1.px+direct[i][0];p2.py=p1.py+direct[i][1];
if(p2.check2()&&visit[p2.px][p2.py]==0&&graph[p2.px][p2.py]!=1&&!(p2.px==per1.x&&p2.py==per1.y)){ //注意除了墙壁前一状态的箱子(即还未被推动的箱子)的位置也不能走
que.push(p2);
visit[p2.px][p2.py]=1;
}
}
}
return false;
}
int bfs_box(){
queue<struct node>que;
que.push(s);
while(!que.empty()){
struct node cur=que.front();
que.pop();
if(graph[cur.x][cur.y]==3)
return cur.time;
for(int i=0;i<4;i++){
struct node next;
next.x=cur.x+direct[i][0];next.y=cur.y+direct[i][1];next.time=cur.time+1;
if(next.check1()&&graph[next.x][next.y]!=1&&!hush[cur.x][cur.y][i]){
next.px=cur.x-direct[i][0];
next.py=cur.y-direct[i][1];
if(next.check2()&&bfs_per(cur,next)){
que.push(next);
hush[cur.x][cur.y][i]=1;
}
}
}
}
return -1;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
memset(hush,0,sizeof(hush));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&graph[i][j]);
if(graph[i][j]==2){
s.x=i;s.y=j;s.time=0;
}
if(graph[i][j]==4){
s.px=i;s.py=j;
}
}
}
printf("%d\n",bfs_box());
}
}