@@ -60,27 +60,46 @@ $$K(i,\omega) = \max \{K(i-1, \omega), K(i-1, \omega - \omega_i) + v_i\}$$
6060
6161这里的分析是以容量递推的,但是在容量特别大时,我们可能需要以价值作为转移方程。定义状态` dp[i + 1][j] ` 为前` i ` 个物品中挑选出价值总和为` j ` 时总重量的最小值(所以对于不满足条件的索引应该用充分大的值而不是最大值替代,防止溢出)。相应的转移方程为:前` i - 1 ` 个物品价值为` j ` , 要么为` j - v[i] ` (选中第` i ` 个物品). 即` dp[i + 1][j] = min{dp[i][j], dp[i][j - v[i]] + w[i]} ` . 最终返回结果为` dp[n][j] ≤ W ` 中最大的 j.
6262
63+ ## 扩展
64+
65+ 以上我们只是求得了最终的最大获利,假如还需要输出选择了哪些项如何破?
66+
67+ 以普通的01背包为例,如果某元素被选中,那么其必然满足` w[i] > j ` 且大于之前的` dp[i][j] ` , 这还只是充分条件,因为有可能被后面的元素代替。保险起见,我们需要跟踪所有可能满足条件的项,然后反向计算有可能满足条件的元素,有可能最终输出不止一项。
68+
6369### Java
6470
6571``` java
6672import java.util.* ;
6773
6874public class Backpack {
6975 // 01 backpack with small datasets(O(nW), W is small)
70- public static int backpack (int W , int [] w , int [] v ) {
76+ public static int backpack (int W , int [] w , int [] v , boolean [] itemTake ) {
7177 int N = w. length;
7278 int [][] dp = new int [N + 1 ][W + 1 ];
79+ boolean [][] matrix = new boolean [N + 1 ][W + 1 ];
7380 for (int i = 0 ; i < N ; i++ ) {
7481 for (int j = 0 ; j <= W ; j++ ) {
7582 if (w[i] > j) {
7683 // backpack cannot hold w[i]
7784 dp[i + 1 ][j] = dp[i][j];
7885 } else {
7986 dp[i + 1 ][j] = Math . max(dp[i][j], dp[i][j - w[i]] + v[i]);
87+ // pick item i and get value j
88+ matrix[i][j] = (dp[i][j - w[i]] + v[i] > dp[i][j]);
8089 }
8190 }
8291 }
8392
93+ // determine which items to take
94+ for (int i = N - 1 , j = W ; i >= 0 ; i-- ) {
95+ if (matrix[i][j]) {
96+ itemTake[i] = true ;
97+ j -= w[i];
98+ } else {
99+ itemTake[i] = false ;
100+ }
101+ }
102+
84103 return dp[N ][W ];
85104 }
86105
@@ -141,9 +160,15 @@ public class Backpack {
141160 int [] w1 = new int []{2 , 1 , 3 , 2 };
142161 int [] v1 = new int []{3 , 2 , 4 , 2 };
143162 int W1 = 5 ;
163+ boolean [] itemTake = new boolean [w1. length + 1 ];
144164 System . out. println(" Testcase for 01 backpack." );
145- int bp1 = backpack(W1 , w1, v1); // bp1 should be 7
165+ int bp1 = backpack(W1 , w1, v1, itemTake ); // bp1 should be 7
146166 System . out. println(" Maximum value: " + bp1);
167+ for (int i = 0 ; i < itemTake. length; i++ ) {
168+ if (itemTake[i]) {
169+ System . out. println(" item " + i + " , weight " + w1[i] + " , value " + v1[i]);
170+ }
171+ }
147172
148173 System . out. println(" Testcase for 01 backpack with large W." );
149174 int bp2 = backpack2(W1 , w1, v1); // bp2 should be 7
@@ -165,4 +190,4 @@ public class Backpack {
165190- Chapter 6.4 Knapsack * Algorithm - S. Dasgupta*
166191- [ 0019算法笔记——【动态规划】0-1背包问题 - liufeng_king的专栏] ( http://blog.csdn.net/liufeng_king/article/details/8683136 )
167192- [ 崔添翼 § 翼若垂天之云 › 《背包问题九讲》2.0 alpha1] ( http://cuitianyi.com/blog/%E3%80%8A%E8%83%8C%E5%8C%85%E9%97%AE%E9%A2%98%E4%B9%9D%E8%AE%B2%E3%80%8B2-0-alpha1/ )
168-
193+ - [ Knapsack.java ] ( http://introcs.cs.princeton.edu/java/96optimization/Knapsack.java.html )
0 commit comments