这到题目的基本思路就是再开一维数组,dp[i][j][k]代表前i个物品在j重量下的第k解,那么dp[i][j][k]可能的取值有dp[i-1][j][1..k]和dp[i-1][j-w[i]][1..k]+v[i]两个来源,这样只需要将上面两个来源按照大小依次排进dp[i][j][k]之中,同时注意排重操作就可以。
题目链接:https://vjudge.net/problem/HDU-2639
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int dp[1005][32];
int ncase;
int cntn , cntw , cntk;
int v[105] , w[105];
void solve () {
int a[32] , b[32];
for (int i = 1 ; i <= cntn ; i++) {
for (int j = cntw ; j >= w[i] ; j--) {
for (int k = 1 ; k <= cntk ; k++) {
a[k] = dp[j-w[i]][k]+v[i];
b[k] = dp[j][k];
}
a[cntk+1] = b[cntk+1] = -1;
int ca , cb , cz;
ca = cb = cz = 1;
while (cz <= cntk && (a[ca] != -1 | b[cb] != -1)) {
if (a[ca] > b[cb]) dp[j][cz] = a[ca++];
else dp[j][cz] = b[cb++];
if (dp[j][cz] != dp[j][cz-1]) cz++;
}
}
}
printf ("%d\n" , dp[cntw][cntk]);
}
int main () {
scanf("%d" , &ncase);
while (ncase--) {
memset(dp,0,sizeof(dp));
scanf("%d%d%d" , &cntn , &cntw , &cntk);
for (int i = 1 ; i <= cntn ; i++)
scanf("%d" , &v[i]);
for (int i = 1 ; i <= cntn ; i++)
scanf("%d" , &w[i]);
solve();
}
}