HDU 1254 推箱子(bfs+优先队列)

推箱子

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值