(不易)POJ-2392 sort预处理+多重部分和

本文针对一组牛上太空的问题,通过多重背包算法实现最优高度构建。文章详细解释了如何结合贪心策略进行排序,并通过动态规划解决完全背包问题,提供了一段完整的C++代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:一群牛要上太空,给出n种石块,每种石块给出单块高度h_i,使用第i种石头后高度不能超过a_i,数量c_i,要求用这些石块能组成的最大高度


题目链接:点击打开链接


分析:

这个问题为典型的多重部分和,也属于完全背包可行性问题。与裸的多重部分和相比,多了一个条件a_i,所以不能再裸多重部分和的代码了。

根据贪心的思想,对于a_i小的当然是堆在越下面越好,所以不妨先对a_i升序排序,这时当检查到第i种石头时,可以组成的最大高度肯定为a_i,因为a_i为前i种里的最大值。这个时候再裸上一个多重部分和的模板就好了。

状态:dp[i][j]:前i种石头且当前正使用第i种堆出高度j最多剩下多少第i种石头

转移:

若dp[i-1][j]>=0,即前i-1种可以配成j,所以根本用不到第i种,所以剩余C_i种  dp[i][j]=C_i

若j<a[i] || dp[i][j-a[i]]<=0,由于dp[i-1][j]<0,所以要想配成j起码得要有第i种,若j<a[i]则第i种用不到,所以前i种仍配不到j,若dp[i][j-a[i]]<=0,则说明配成j-a[i]时第i种已经无剩余或者甚至无法配成j-a[i],更别说配成j了,        dp[i][j]=-1

其他情况,由于a[i]还有剩,所以dp[i][j]相当于在dp[i][j-a[i]]的基础上多使用了一个a[i],此时   dp[i][j]=dp[i][j-a[i]]-1



附上代码:

#include<iostream>
#include<algorithm>
using namespace std;
struct Block{ int h, a, c; }block[405];
int dp[40005];      //dp[i][j]:前i种且当前正使用第i种堆出j时第i种最多剩余的个数 
int n, ans = 0;       
bool cmp(Block &aa, Block &bb){ return aa.a < bb.a; }
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d%d%d", &block[i].h, &block[i].a, &block[i].c);
	sort(block + 1, block + n + 1, cmp);
	memset(dp, -1, sizeof dp);
	dp[0] = 0;
	for (int i = 1; i <= n; i++)
		for (int j = 0; j <= block[i].a; j++)
			if (dp[j] >= 0) dp[j] = block[i].c;
			else if (j < block[i].h || dp[j - block[i].h] <= 0) dp[j] = -1;
			else dp[j] = dp[j - block[i].h] - 1;
	for (int i = 1; i <= block[n].a; i++)
		if (dp[i] >= 0) ans = i;
	printf("%d\n", ans);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值