算法
¶动态规划算法
¶总方法论 - 动态规划五部曲
- 确定DP数组(DP table)以及下标的含义
- 动态规划的核心在于理解和明确DP数组所表示的含义
- 在进行动态规划递推公式推导的时候要紧紧围绕着DP数组的含义
- 推导递推公式
- 推导递推公式的关键在于找到当前状态可以由哪些状态转移而来
- 要搞清楚可以从哪些状态转移来就要紧紧围绕着DP数组的含义
- dp数组如何初始化
- 在确定递推公式之后在进行初始化
-
¶确定遍历顺序
- 举例推导dp数组
- 如果动规结果不正确,最好的方式是打印出来DP数组的值,分析与预期结果哪里不正确
¶动态规划:01背包理论基础
¶01背包问题基本题目(二维数组解法):
题目描述
有个背包可承受重量N,现有T件物品,每件物品重量为Wi,价值为Vi ,每件物品只有一个,这个背包可以装载物品的最大价值是多少?
输入格式
第一行,两个整数,分别表示N和T,用空格隔开(N≤1000,T≤100)
接下来T行,每行两个整数,分别表示T件物品的重量Wi和价值Vi(1≤Wi,Vi≤100)
输出格式
一行,表示这个背包可以装载物品的最大价值
输入输出样例
输入样例1:
100 5
77 92
22 22
29 87
50 46
99 90
输出样例1:
133
模拟过程(画图)可以参考:背包理论基础01背包-1
分析
-
状态转移过程
dp[i][j]的转移可以由它的上方(dp[i-1][j])和左上方转移(dp[i-1][j-weights[i]] + values[i])而来
-
dp[0][j]
和dp[i][0]
的初始化dp[i][0]
初始化为0,因为在背包载重为0时总价值肯定全为0dp[0][j]
第一行表示装第一个物品后背包的价值(对应dp[0][i] = values[0]
)
如果背包的载重装不了第一个物品则价值还是为零(对应i = weights[0]
,也就是从背包载重能满足第一个物品开始
-
DP数组的其他值该如何初始化?
- 都可以,0、-1、-100都没有关系,因为DP数组的其他值都是由之前的状态转移而来的
-
遍历顺序,填充DP数组
- 那么问题来了,先遍历 物品还是先遍历背包重量呢?
- 其实都可以!! 但是先遍历物品更好理解。
- 物品的遍历从第二个开始
- 背包重量的遍历从0开始
- 如果背包重量小于当前物品的重量,那么就继承
dp[i - 1][j]
的值
if(j < weights[i]) dp[i][j] = dp[i-1][j];
题解:
1 |
|
¶01背包问题(一维数组解法)
注意点:
- 为什么可以不对第一行进行初始化
因为在后续的滚动过程中就相当于完成了这个初始化过程 - dp[i] 的含义容量为i的背包,所背的物品价值可以最大为dp[i]
- 为什么在使用滚动数组的时要倒序遍历背包容量
因为如果使用正序遍历,在计算dp[i]时会用到dp[i-1],而这时dp[i-1]已经被修改了,
倒序遍历是为了保证物品i只被放入一次,如果一旦正序遍历了,那么物品0就会被重复加入多次! - 使用滚动数组二重循环能否调换顺序
不可以!
因为一维dp的写法,背包容量一定是要倒序遍历(原因上面已经讲了),如果遍历背包容量放在上一层,那么每个dp[j]就只会放入一个物品,即:背包里只放入了一个物品。
题解
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hiyoung'blog!