01背包基础
问题
有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
假设背包的最大重量为4
物品的信息如下
物品下标 | 物品重量 | 物品价值 |
---|---|---|
0 | 1 | 15 |
1 | 3 | 20 |
2 | 4 | 30 |
动态规划解决
对于背包问题,你先解决小背包(子背包)问题,再逐步解决原来的问题。
根据物品重量确定好划分背包大小的粒度
本问题中背包的最大容量为4,物品的重量依次是1,3,4
因此小背包的容量可以从零开始依次化为0,1,2,3,4
由此可以画出如下表格
dp[i][j]表示从物品下标为0到i物品中任选几件(每种物品只有一个)放入背包中,背包中的物品的最大价值。
接下来我们将依次将这个表格填写完整
对于第一行
我们只取物品0
当背包容量为零的时候显然什么也装不下,因此价值为0
当背包的容量为1,2,3,4时背包可以将物品零加入背包内价值为15
对于第二行
取物品时从物品0,物品1中选取
背包重量为0时价值为0
背包重量为1,2时,由于物品1的重量为3,背包依然装不下,所以背包还是只能装物品0,背包能装的物品的最大价值还是15
即dp[i][j]=dp[i-1][j]
当背包容量为3时,此时背包可以放下物品1了
但是背包要放物品1就不能放物品0,因此要分别考虑放物品1的情况和不放物品1的情况
不放物品1
就是背包重量为3,只放物品0的情况
既是dp[i][j]=dp[i-1][j]
放物品1
那我们要计算当前背包容量刨去放置物品1的容量后能装取的物品的最大价值
我们要记住,我们每填的一格都是在当前情况下的最优解决方案。所以上述的最大价值既是dp[i-1][j-物品1的重量](对于下标i-1,由于刨去了物品1的重量所以必然没有将物品1放入背包中)再加上物品一的价值。dp[i][j]=dp[i][j]=dp[i-1][j-物品1的重量]+物品1的价值
然后取这两个的最大值即
dp[i][j]=max( dp[i-1][j],dp[i-1][j-物品1的重量]+物品1的价值 )
这也是该问题的递推公式
对于第三行即物品2采取相同的策略
代码
public static void main(String[] args) {
int[] weight = {1, 3, 4};
int[] value = {15, 20, 30};
int bagsize = 4;
testweightbagproblem(weight, value, bagsize);
}
public static void testweightbagproblem(int[] weight, int[] value, int bagsize){
int wlen = weight.length, value0 = 0;
//定义dp数组:dp[i][j]表示背包容量为j时,前i个物品能获得的最大价值
int[][] dp = new int[wlen + 1][bagsize + 1];
//初始化:背包容量为0时,能获得的价值都为0
for (int i = 0; i <= wlen; i++){
dp[i][0] = value0;
}
//遍历顺序:先遍历物品,再遍历背包容量
for (int i = 1; i <= wlen; i++){
for (int j = 1; j <= bagsize; j++){
if (j < weight[i - 1]){
dp[i][j] = dp[i - 1][j];
}else{
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i - 1]] + value[i - 1]);
}
}
}
//打印dp数组
for (int i = 0; i <= wlen; i++){
for (int j = 0; j <= bagsize; j++){
System.out.print(dp[i][j] + " ");
}
System.out.print("\n");
}
}