有n件物品和一个最大承重为W的背包,每件物品的重量是w[i],价值是v[i] 在保证总重量不超过W的前提下,选择某些物品装入背包,背包的最大总价值是多少?
注意:每个物品只有一件,也就是每个物品只能选择0件或者1件
分析:
假设:W=10,有5件物品,重量和价值如下:
重量 | 价值 | |
---|---|---|
1 | 2 | 6 |
2 | 2 | 3 |
3 | 6 | 5 |
4 | 5 | 4 |
5 | 4 | 6 |
dp数组的计算结果如下表
上图中 横轴 j表示 当前最大承重, 纵轴 i 表示 物品编号,产生的值则表示 当前最大总价值
i\j 0 1 2 3 4 5 6 7 8 9 10 0 0 0 0 0 0 0 0 0 0 0 0 1(w[1]=2, v[1]=6) 0 0 6 6 6 6 6 6 6 6 6 2(w[2]=2, v[2]=3) 0 0 6 6 9 9 9 9 9 9 9 3(w[3]=6, v[3]=5) 0 0 6 6 9 9 9 9 11 11 14 4(w[4]=5, v[4]=4) 0 0 6 6 9 9 9 10 11 13 14 5(w[5]=4, v[5]=6) 0 0 6 6 9 9 12 12 12 15 15
例如:当最大承重为 7 ,可选物品编号为 {1,2,3,4} 时,可选择的最大总价值为 10
解决思路:
在01背包问题中,获取物品只存在 获取 或者 不获取 这两种可能性
根据我们上图罗列出来的表格来看
如果可以选择这一件物品的话 :j > w[i], 即:当前最大承重 > 当前物品重量
- 如果不选择的话:dp(i, j) = dp(i - 1, j)
- 如果选择了的话:dp(i, j) = v[i] + dp(i - 1, j - w[i])
两者取价值最大的数:Max(dp(i, j) = dp(i - 1, j), dp(i, j) = v[i] + dp(i - 1, j - w[i]))
如果不可以选择这件物品的话:j<w[i], 即:dp(i, j) = dp(i - 1, j)
代码实现:
public class Bag2 {
public static int maxValue(int[] values, int[] weights, int max){
if (values == null || values.length == 0){
return 0;
}
if (weights == null || weights.length == 0){
return 0;
}
if (values.length != weights.length || max <= 0){
return 0;
}
//dp数组
int[][] dp = new int[values.length + 1][max + 1];
for (int i = 1; i <= values.length; i++) {
for (int j = 1; j <= max; j++){
//选择的物品超过最大承重
if(j < weights[i - 1]){
//最大价值 = 上一轮最大价值
dp[i][j] = dp[i - 1][j];
} else {
dp[i][j] = Math.max(dp[i - 1][j], values[i - 1] + dp[i - 1][j - weights[i - 1]]);
}
}
}
return dp[values.length][max];
}
public static void main(String[] args) {
int[] values={6,3,5,4,6};
int[] weights={2,2,6,5,4};
int max=10;
System.out.println(maxValue(values,weights,max));
}
}
时间复杂度为:O(i * j)
可以看出动态规划计算的值是 上次的某个值+这次的值,是一种以空间换时间的算法。