理论
有N件物品和⼀个最多能被重量为W 的背包。第i件物品的重量是weight[i],得到的价值是
value[i] 。每件物品只能⽤⼀次,求解将哪些物品装⼊背包⾥物品价值总和最⼤。
思路
-
确定dp数组的定义
在⼀维dp数组中,dp[j]表⽰:容量为j的背包,所背的物品价值可以最⼤为dp[j]。
- ⼀维dp数组的递推公式
dp[j]可以通过dp[j - weight[j]]推导出来,dp[j - weight[i]]表⽰容量为j - weight[i]的背包所背
的最⼤价值。
dp[j - weight[i]] + value[i] 表⽰ 容量为 j - 物品i重量 的背包 加上 物品i的价值。(也就是容
量为j的背包,放⼊物品i了之后的价值即:dp[j])
此时dp[j]有两个选择,⼀个是取⾃⼰dp[j],⼀个是取dp[j - weight[i]] + value[i],指定是取
最⼤的,毕竟是求最⼤价值,所以递归公式为:
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
- ⼀维dp数组如何初始化
关于初始化,⼀定要和dp数组的定义吻合,否则到递推公式的时候就会越来越乱。
dp[j]表⽰:容量为j的背包,所背的物品价值可以最⼤为dp[j],那么dp[0]就应该是0,因为
背包容量为0所背的物品的最⼤价值就是0。
那么dp数组除了下标0的位置,初始为0,其他下标应该初始化多少呢?
dp数组在推导的时候⼀定是取价值最⼤的数,如果题⽬给的价值都是正整数那么⾮0下标都
初始化为0就可以了,如果题⽬给的价值有负数,那么⾮0下标就要初始化为负⽆穷。
这样才能让dp数组在递归公式的过程中取的最⼤的价值,⽽不是被初始值覆盖了。
那么我假设物品价值都是⼤于0的,所以dp数组初始化的时候,都初始为0就可以了。
- ⼀维dp数组遍历顺序
for(int i = 0; i < weight.size(); i++) { // 遍历物品
for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
倒叙遍历是为了保证物品i只被放⼊⼀次