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
", Solve());
52     }
53     return 0;
54 }
原文地址:https://www.cnblogs.com/shijianming/p/4140824.html