在有容量限制的情况下装下最大价值的物品:
// 设置n个物体重量和对应的价值
int w[] = {0, 1, 2, 5, 4, 3};
int v[] = {0, 1, 2, 3, 4, 5};
// 背包容量
int m = 10;
结果导论:如果在取 [a1,a2...ak] [ a 1 , a 2 . . . a k ] 时价值最大,那么在限制重量为 m−w[ak] m − w [ a k ] 时(也就是还未考虑 ak a k 时)取得最大价值的集合必有 [a1,...ak−1] [ a 1 , . . . a k − 1 ] 。
因此,若以dp表示价值,我们只要得到子问题 dp[k−1][m−w[ak]] d p [ k − 1 ] [ m − w [ a k ] ] 的最大值,就可以得到 dp[k][m] d p [ k ] [ m ] 即结果集所取得的最大值。
但是我们不知道1-k中的实际数值,于是遍历 i∈[1,n],j∈[1,m] i ∈ [ 1 , n ] , j ∈ [ 1 , m ] 来得到 dp[n][m] 的最大值。在遍历过程如何确定dp[i][j] 的值呢?
首先如果在限制重量为 j 的情况下不能装入,那么有 i 和没有 i 是没有区别的, 于是 dp[i][j]=dp[i−1][j] d p [ i ] [ j ] = d p [ i − 1 ] [ j ] 。
其次如果能添加 ,说明限制重量 j>=w[i] j >= w [ i ] ,之前的重量最大为 j−w[i] j − w [ i ] , 因此添加后的价值为 dp[i][j]=dp[i−1][j−w[i]]+v[i] d p [ i ] [ j ] = d p [ i − 1 ] [ j − w [ i ] ] + v [ i ] ,但是比较 dp[i−1][j−w[i]] d p [ i − 1 ] [ j − w [ i ] ] 和 dp[i−1][j] d p [ i − 1 ] [ j ] 显然重量的限制不一样,也就说可能为了装入 i 而放弃了某些物品。于是考虑 i 物品但是装不装入由 dp[i][j]=max(dp[i−1][j],dp[i−1][j−w[i]]+v[i]) d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w [ i ] ] + v [ i ] ) 决定。
// 设置重量和对应的价值
int w[] = {0, 1, 2, 5, 4, 3};
int v[] = {0, 1, 2, 3, 4, 5};
// 背包容量
int m = 10;
int len = w.length-1;
// dp表示在考虑前i情况下在重量j时能够实现的最大价值
// dp[i-1][j-w[i]]表示在还未考虑i的且能装下i的最大值
int dp[][] = new int[len+1][m+1];
for(int i=1; i<=len; i++){
for(int j=1; j<=m; j++){
// 当能装入i且装入价值更大时,放弃某些物品,腾出w[i]空间装入i
if (j>=w[i] && (dp[i-1][j-w[i]]+v[i] > dp[i-1][j])) {
dp[i][j] = dp[i-1][j-w[i]]+v[i];
}
// 否则不装入
else {
dp[i][j] = dp[i-1][j];
}
}
}
System.out.println(dp[len][m]);
逆推得到装入的物品;
int j = m;
for(int i=len; i>0; i--){
// 判断是否装入了i物品
if (dp[i][j] > dp[i-1][j]) {
System.out.println(i);
j =j-w[i];
}
}
另外有一种一维数组的逆推方法但是不能找到装入的物品:
https://blog.csdn.net/hearthougan/article/details/53869671