这个问题的标题是熟悉的,不是吗?是的,如果你参加了“新秀杯”比赛,你必须看起来这个标题。如果你以前没见过,没关系,我会给你一个链接:
这里是链接: http : //acm.hdu.edu.cn/showproblem.php?pid=2602
今天我们不是想要骨骼的最大值,而是K的最大值我们认为,我们考虑两种获得相同的骨骼价值的方法是一样的。这意味着,它将是从第1个最大值,第2个最大值到第K个最大值的严格递减序列。
如果不同值的总数小于K,则输出0。
这里是链接: 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个整数。
其次是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这道题目;这就会深入到学习方法的问题,在此不敢吹逼;