Bone Collector II

本文介绍了一种解决多重背包问题的特殊场景——求第K优解的方法。通过使用二维DP数组来记录每种选择的状态,文章详细阐述了如何实现这一目标,并提供了完整的代码示例。

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

这个问题的标题是熟悉的,不是吗?是的,如果你参加了“新秀杯”比赛,你必须看起来这个标题。如果你以前没见过,没关系,我会给你一个链接:

这里是链接: http  : //acm.hdu.edu.cn/showproblem.php?pid=2602

今天我们不是想要骨骼的最大值,而是K的最大值我们认为,我们考虑两种获得相同的骨骼价值的方法是一样的。这意味着,它将是从第1个最大值,第2个最大值到第K个最大值的严格递减序列。

如果不同值的总数小于K,则输出0。

输入

第一行包含整数T,个案数。
其次是T个案,每个案例三行,第一行包含两个整数N,V,K(N <= 100,V <= 1000,K <= 30),表示骨数和他的行李的体积我们需要K 第二行包含表示每个骨骼的值的N个整数。第三行包含表示每个骨的体积的N个整数。

输出

每行一个整数表示总值的第K个最大值(该数字将小于2  31 )。

样品输入

3
5 10 2
1 2 3 4 5
5 4 3 2 1
5 10 12
1 2 3 4 5
5 4 3 2 1
5 10 16
1 2 3 4 5
5 4 3 2 1

示例输出

12
2
0
此类问题属于多重背包问题;
普通01背包只找到最优路径,今天这个问题关键在于寻找第几个最优解,这就需要用二维背包来进行记录: dp[100][100]; 
其它的主题思路和01背包一样;
记录路径还要依次排,就要对01背包步骤进行拆分,并开A[1000],B[1000];进行记录;最后由dp[][]来记录背包最优情况;
如果对01背包思想没彻底理解,就无法写出这个程序,就想我,参考多位大牛思路,代码,disscuss,才理解;
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
//由于vs编译器限制数组一律开在main函数外;
int dp[2000][2000], val[2000], vol[2000], A[2000], B[2000];
using namespace std;
int main()
{
	int t;
	int n, v, k;
	int i, j;
	while (cin >> t)
	{
		while (t--)
		{
			cin >> n >> v >> k;
			for (i = 1; i <= n; i++) cin >> val[i];
			for (i = 1; i <= n; i++) cin >> vol[i];
			memset(dp,0,sizeof(dp));
			for (i = 1; i <= n; i++)
			{
				for (j = v; j >= vol[i]; j--)
				{
					int kk;
					for (kk = 1; kk <= k; kk++)
					{
						A[kk] = dp[j - vol[i]][kk] + val[i];
						B[kk] = dp[j][kk];
					}
					int x, y, z;
					x = y = z = 1;
					A[kk] = B[kk] = -1;
					while (z <= k && (x <= k || y <= k))
					{
						if (A[x] > B[y])
							dp[j][z] = A[x++];
						else
							dp[j][z] = B[y++];
						if (dp[j][z] != dp[j][z - 1])
							z++;
					}
				}
			}
			cout << dp[v][k] << endl;
		}
	}


	return 0;
}
备注:习惯问题,每个人代码风格都不同,因此我只贴代码和思路,不会再代码中添加备注方便别人阅读;
这对学习者是非常不好的,会一字一言的按别人的代码打下来,内心不自主的暗示自己已经把这个代码内化,其实恰好没有,过几天他定没法再次很顺利ac这道题目;这就会深入到学习方法的问题,在此不敢吹逼;






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值