推箱子
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 9779 Accepted Submission(s): 2873
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+优先队列
从人为起点开始bfs,如果人走的下一步是箱子所在的坐标,说明找到了箱子,箱子的坐标为当前所搜方向上人的坐标前进一格(就是推一格箱子,箱子前进的方向和人前进的方向是一致的),判断箱子是否到达了目的地,如果是则输出箱子移动的最少步数,到不了就输出-1。应该按照所走步数多少决定出队列顺序,所以用优先队列处理下。
(人从起点找箱子是不计数的)
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<queue>
using namespace std;
int n,m;
int f[4][2]={0,1,1,0,0,-1,-1,0};
int vis[9][9][9][9];
int mat[9][9];
struct node{
int x,y;//人坐标
int bx,by;//箱子坐标
int temp;//推箱子步数
bool friend operator<(const node &a, const node &b)
{//必须优先队列,步数小优先
return a.temp>b.temp;
}
}start;//起点
void bfs()
{
node s,t;
priority_queue<node>q;
memset(vis,0,sizeof(vis));
vis[start.x][start.y][start.bx][start.by]=1;
start.temp=0;
q.push(start);
while(!q.empty())
{
t=q.top();
q.pop();
if(mat[t.bx][t.by]==3)
{//终点
printf("%d\n",t.temp);
return;
}
for(int i=0;i<4;i++)
{
s.x=t.x+f[i][0];//人的下一步
s.y=t.y+f[i][1];
if(s.y>=1&&s.x>=1&&s.y<=m&&s.x<=n&&mat[s.x][s.y]!=1)
{
s.bx=t.bx;//不能推时,箱子的坐标
s.by=t.by;
s.temp=t.temp;
if(s.x==t.bx&&s.y==t.by)
{//能推箱子
int tbx=t.bx+f[i][0];
int tby=t.by+f[i][1];
if(tbx>=1&&tbx<=n&&tby>=1&&tby<=m&&mat[tbx][tby]!=1)
{//推完箱子判断是否过界,不过界,推数加1
s.bx=tbx;//更新箱子坐标
s.by=tby;
s.temp++;
}
}
if(!vis[s.x][s.y][s.bx][s.by])
{
vis[s.x][s.y][s.bx][s.by]=1;
q.push(s);
}
}
}
}
printf("-1\n");
return;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&mat[i][j]);
if(mat[i][j]==4)
{
start.x=i;start.y=j;
mat[i][j]=0;
}
if(mat[i][j]==2)
{
start.bx=i;start.by=j;
mat[i][j]=0;
}
}
}
bfs();
}
return 0;
}