题目大意:求第k大的01背包(相同价值的去掉)
解题思路:还是按照01背包的思路来,不过数组要多加一维,另一维表示的是第几大
状态转移的时候,用两个数组纪录一下转移的的大小:一个纪录的是放该物品的第k大的价值,另一个纪录的是不放该物品的第k大的价值
接着再把这两个数组比较一下,取到所需数量的价值即可
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
const int V = 1010;
int val[N], volume[N];
int dp[V][35], A[35], B[35];
int n, m, k;
void init() {
scanf("%d%d%d", &n, &m, &k);
for (int i = 0; i < n; i++)
scanf("%d", &val[i]);
for (int i = 0; i < n; i++)
scanf("%d", &volume[i]);
}
void solve() {
memset(dp, 0, sizeof(dp));
for (int i = 0; i < n; i++)
for (int j = m; j >= volume[i]; j--) {
for (int no = 1; no <= k; no++) {
A[no] = dp[j - volume[i]][no] + val[i];
B[no] = dp[j][no];
}
A[k + 1] = B[k + 1] = -1;
int a = 1, b = 1, c = 1;
while (c <= k && (A[a] != -1 || B[b] != -1)) {
if (A[a] > B[b]) {
dp[j][c] = A[a]; a++;
}
else {
dp[j][c] = B[b]; b++;
}
if (dp[j][c] != dp[j][c - 1])
c++;
}
}
printf("%d\n", dp[m][k]);
}
int main() {
int test;
scanf("%d", &test);
while (test--) {
init();
solve();
}
return 0;
}