推箱子
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 9254 Accepted Submission(s): 2717
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
/*
HDU 推箱子
精简的解题报告
此题也真算是双向BFS的一个简单模板了(bfs水题?),要点是如何存储人与箱子当前状态的步数最优解,看见m,n的范围想到用数组大法(四维数组)
总结经验:
1.数据不大时涉及到储存状态的,如发现有DP性质优先考虑状态压缩,如没有DP性质优先考虑数组储存而不是结构体(真的是难以驾驭结构体啊)
2.双向bfs特点:有两个动点相关,且一个点的状态由另一点状态决定,两者具有可变性
下为模板
*/
#include <iostream>
#include <queue>
#define maxn 10
#define INF 0xfffffff
using namespace std;
//友情提示,bfs的调试难在放置各判断是否压入队列的语句 的 相关位置,发现不了就爆-1,发现了并改正了便可直达病灶
int n,m,i,j,k,l;//定义能用的全局变量
int dir[4][2]={0,1,0,-1,-1,0,1,0};//方向
int vst[maxn][maxn][maxn][maxn];//储存当前状态的step值,并对之后最终的结果作比较得出答案
int graph[maxn][maxn];//。。。
struct node{
int x,y,nx,ny,step;
};
node start;
bool man(node now)//判断人在当前状态下是否满足条件
{
return now.x>=0&&now.y>=0&&now.x<m&&now.y<n&&graph[now.x][now.y]!=1&&now.step<vst[now.x][now.y][now.nx][now.ny];//当前step如大于等于原有状态便不考虑压入队列
}
bool box(node now)
{
return now.nx>=0&&now.ny>=0&&now.nx<m&&now.ny<n&&graph[now.nx][now.ny]!=1&&now.step<vst[now.x][now.y][now.nx][now.ny];//同上
}
int bfs()
{
node now,nex;
int ans=INF;//记得初始化答案最大值
queue <node> Q;
Q.push(start);
vst[start.x][start.y][start.nx][start.ny]=1;//开局的起点一定要定义为可操作的,不然爆-1 (人在起点必然会走一步)
while(!Q.empty())
{
now=Q.front();
Q.pop();
if(graph[now.nx][now.ny]==3)
{
ans=min(ans,now.step);//到达终点后决定答案
}
for(i=0;i<4;i++)
{
nex=now;
nex.x+=dir[i][0];
nex.y+=dir[i][1];
if(man(nex))
{
if(nex.x==nex.nx&&nex.y==nex.ny)//如果箱子与人重合,箱子必往人的行走方向(bfs当前方向)再走一步
{
nex.nx+=dir[i][0];
nex.ny+=dir[i][1];
nex.step++;//step++不能放在判断box当前位置是否合法后,因为将不满足bool box()的最后一个判断条件
if(box(nex))
{
vst[nex.x][nex.y][nex.nx][nex.ny]=nex.step;//更新当前状态的最优解
Q.push(nex);
}
}else//不重合?
{
vst[nex.x][nex.y][nex.nx][nex.ny]=nex.step;//改变原有vst[当前状态]的INF值,防爆-1,step没有++
Q.push(nex);
}
}
}
}
return ans;
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>m>>n;
for(i=0; i<maxn; i++)
for(j=0; j<maxn; j++)
for(k=0; k<maxn; k++)
for(l=0; l<maxn; l++)
vst[i][j][k][l] = INF;
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
cin>>graph[i][j];
if(graph[i][j]==4)
{
start.x=i;start.y=j;start.step=0;
}else if(graph[i][j]==2)
{
start.nx=i;start.ny=j;
}
}
}
k=bfs();
if(k==INF)cout<<-1<<endl;
else cout<<k<<endl;
}
}