动态规划–01背包
一、 问题描述
有N件物品和⼀个最多能背重量为V 的背包。第i件物品的重量是v[i],得到的价值是w[i] 。每件物品只能⽤⼀次,求解将哪些物品装⼊背包⾥物品价值总和最⼤。
二、 分析步骤
这里我们利用Carl哥的动规五部曲。
1. 确定dp数组及其下标的含义
i:第几个物品
j:背包容量
dp[i][j]:拿到第i个物品时,容量为j的背包内,物品价值总和的最大值。
2. 列举推导dp数组
3. 确定递推公式
4. dp数组初始化
初始化一般考虑dp[i][0]和dp[0][j]。
如果背包容量j为0的话,⽆论是选取哪些物背包价值总和一定为零,因为都放不下。如果物品种类i为1的话,当j<v[i]时,dp[i][j]=0;当j≥v[i]时,dp[i][j]=v[1]。
说白了都初始化为零也不会错。
5. 确定遍历过程
顺序考虑两部分,一个是i和j的先后顺序,另一个是遍历从哪到哪。
这里i和j的先后都可以,遍历i要从1开始,因为要遍历i-1,遍历到最后一个物品N;如果从0会数组越界;j则可以从零开始,遍历到最大的一个背包V。
三、 滚动数组
1. 压缩状态
因为通过递推公式可以观察到dp[i][j]是从dp[i-1][j]推导出来的。形象一点讲就是从dp数组的上一层推出下一层,那么我们可以对数组进行压缩,变成一维数组。
2. 分析步骤
- 确定dp数组及其下标的含义
dp[j]:拿到第i个物品时,容量为j的背包内,物品价值总和的最大值。 - 列举推导dp数组
此时变化的dp一维数组和原二维dp数组是一样的。 - 确定递推公式
这里简单粗暴的将所有关于i的子项去掉了。
- dp数组初始化
和二维数组初始化保持一致。 - 确定遍历过程
先后顺序和i的遍历顺序不用改变,即i从1开始,到N。
通过观察递推公式,如果j从前向后遍历,那么拿到的 就是刷新过的,本层的数据。所以应该从后往前递推,所以j从V开始,到v[i]即可,因为再往前的数组不会改变。