01背包(求前一个的最大价值-->求前K个的最大价值) 之 hdu 2639
// [7/21/2014 Sjm]
/*
此题我想的思路错了,情况考虑漏了。。。
解法是由 求前一个的最大价值-->求前K个的最大价值 的转化。
求前一个最大价值:
dp[i][j] = max(dp[i-1][j], dp[i-1][j-C[i]] + W[i])
求前K个的最大价值
同样,dp[i][j]的前 k 个最大价值,是依赖于 dp[i-1][j] 的前 k 个最大价值和 dp[i-1][j-C[i]] 的前 k 个最大价值所求得的。
由此考虑了所有情况,求出了答案。
*/
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <algorithm> 5 #include <cstring> 6 using namespace std; 7 const int MAX = 100005; 8 const int MAX_N = 105; 9 const int MAX_K = 35; 10 int N, V, K; 11 int arr[MAX_N][2], dp[MAX][MAX_K]; 12 int tep1[MAX_K], tep2[MAX_K]; 13 14 int Solve() { 15 memset(dp, 0, sizeof(dp)); 16 for (int i = 1; i <= N; ++i) { 17 for (int j = V; j >= arr[i][1]; --j) { 18 for (int k = 1; k <= K; ++k) { 19 // 注意:经过此循环,tep1[], tep2[]均是递减排列的。(根据01背包的原理) 20 tep1[k] = dp[j - arr[i][1]][k] + arr[i][0]; 21 tep2[k] = dp[j][k]; 22 } 23 tep1[K + 1] = tep2[K + 1] = -1; 24 int pos1 = 1, pos2 = 1; 25 for (int k = 1; (pos1 <= K || pos2 <= K)&&k <= K;) { 26 if (tep1[pos1] > tep2[pos2]) { dp[j][k] = tep1[pos1++]; } 27 else { dp[j][k] = tep2[pos2++]; } 28 if (dp[j][k] != dp[j][k - 1]) { 29 ++k; 30 } 31 } 32 } 33 } 34 return dp[V][K]; 35 } 36 37 int main() 38 { 39 //freopen("input.txt", "r", stdin); 40 //freopen("output.txt", "w", stdout); 41 int T; 42 scanf("%d", &T); 43 while (T--) { 44 scanf("%d %d %d", &N, &V, &K); 45 for (int i = 1; i <= N; ++i) { 46 scanf("%d", &arr[i][0]); 47 } 48 for (int i = 1; i <= N; ++i) { 49 scanf("%d", &arr[i][1]); 50 } 51 printf("%d\n", Solve()); 52 } 53 return 0; 54 }