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


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于HDU4546问题,还可以使用优先队列(Priority Queue)来解决。以下是使用优先队列的解法思路: 1. 首先,将数组a进行排序,以便后续处理。 2. 创建一个优先队列(最小堆),用于存储组合之和的候选值。 3. 初始化优先队列,将初始情况(即前0个数的组合之和)加入队列。 4. 开始从1到n遍历数组a的元素,对于每个元素a[i],将当前队列中的所有候选值取出,分别加上a[i],然后再将加和的结果作为新的候选值加入队列。 5. 重复步骤4直到遍历完所有元素。 6. 当队列的大小超过k时,将队列中的最小值弹出。 7. 最后,队列中的所有候选值之和即为前k小的组合之和。 以下是使用优先队列解决HDU4546问题的代码示例: ```cpp #include <iostream> #include <vector> #include <queue> #include <functional> using namespace std; int main() { int n, k; cin >> n >> k; vector<int> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } sort(a.begin(), a.end()); // 对数组a进行排序 priority_queue<long long, vector<long long>, greater<long long>> pq; // 最小堆 pq.push(0); // 初始情况,前0个数的组合之和为0 for (int i = 0; i < n; i++) { long long num = pq.top(); // 取出当前队列中的最小值 pq.pop(); for (int j = i + 1; j <= n; j++) { pq.push(num + a[i]); // 将所有加和结果作为新的候选值加入队列 num += a[i]; } if (pq.size() > k) { pq.pop(); // 当队列大小超过k时,弹出最小值 } } long long sum = 0; while (!pq.empty()) { sum += pq.top(); // 求队列中所有候选值之和 pq.pop(); } cout << sum << endl; return 0; } ``` 使用优先队列的方法可以有效地找到前k小的组合之和,时间复杂度为O(nklog(k))。希望这个解法对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值