「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」
前言
我们上篇文章学习了动态规划01背包的问题,本篇文章我们继续学习完全背包。大家可以在学习完01背包的基础上再进行学习,比较其两者的解题差异。
完全背包
完全背包实际由01背包演化而来,01背包中每个物品的个数都是1,而完全背包不限制物品数量,每种物品的数量无限,可以重复加入背包中。
我们来看看完全背包的提问
Q:一共有N种物品,每种物品有无限多个,第i(i从1开始)种物品的重量为w[i],价值为v[i]。在总重量不超过背包承载上限W的情况下,能够装入背包的最大价值是多少?
解题步骤
我们说的解题步骤实际上是动态规划的一个解题步骤
1.定义dp数组
dp数组的定义实际和01背包相同
我们要求的是在总容量为W,物品有N件的情况下,可以取得的最大价值Vmax。有两个变量容量w及物品n,我们设要求的总价值dp[i][j],其中i表示物品可取范围为前i件,即范围[0, i],j表示背包容量。
dp[i][j] // i表示物品可取范围为前i件 j表示背包容量
2.递归公式
完全背包和01背包的差异主要体现在递推公式
依据题目,我们可以重复放入第i件物品,所以我们的最大价值应该对比放入不同件数的最大价值
dp[i][j] = Math.max(dp[i - 1][j - n * w[i]] + n * v[i]) // 0 =< n <= j / w[i] n为整数
有两种不同的递推思路,其中一种不好理解,我也没理解过来,所以就只列出了第二种
3.dp初始化
初始化和01数组相同
在容量为0的时候时候,dp[i][j]肯定为0
dp[i][0] = 0
当所选的物品为0的时候,价值也为0
dp[0][j] = 0
4.dp遍历生成
for (let i = 1; i <= N; i++) {
for (let j = 1; j <= W; j++) {
for (let n = 0; n <= parseInt(j / w[i])) {
dp[i][j] = Math.max(dp[i][j] || 0, dp[i - 1][j - n * w[i]] + n * v[i])
}
}
}
完全背包实例
Q:一共有N种物品,每种物品有无限多个,第i(i从1开始)种物品的重量为w[i],价值为v[i]。在总重量不超过背包承载上限W的情况下,能够装入背包的最大价值是多少?
N = 5;
W = 20;
w = [4, 5, 10, 11, 13];
v = [3, 4, 7, 8, 9];
function knapsack() {
const N = 5;
const W = 43;
const w = [4, 5, 10, 11, 13];
const v = [3, 4, 7, 8, 9];
// 1.定义dp数组
// dp[n][w]表示容量为w的情况下可取前n件物品时的最大价值
const dp = []
// 2.初始化dp数组
// 容量为0时价值为0
for (let i = 0; i <= N; i++) {
dp[i] = []
dp[i][0] = 0
}
// 可取物品为0时价值为0
for (let j = 0; j <= W; j++) {
dp[0][j] = 0
}
// 4.dp遍历生成
// 我们第一层遍历物品
for (let i = 1; i <= N; i++) {
// 第二层遍历容量
for (let j = 1; j <= W; j++) {
// 3.推导公式
// 这边有个注意点是dp[i][j]对应的是可取第i个物品的最大价值
// 但是第i个物品的重量和价值对应的是w[i - 1]和v[i - 1]
for (let n = 0; n <= parseInt(j / w[i - 1]); n++) {
dp[i][j] = Math.max(dp[i][j] || 0, dp[i - 1][j - n * w[i - 1]] + n * v[i - 1])
}
}
}
return dp[N][W]
}
多重背包
我们在完全背包的基础上再了解下多重背包
多重背包也是01背包的一种变形,其问题形式为
Q:一共有N种物品,第i(i从1开始)种物品的数量为K[i],重量为w[i],价值为v[i]。在总重量不超过背包承载上限W的情况下,能够装入背包的最大价值是多少?
可以发现多重背包和完全背包非常相似,主要区别在于物品数量限制。其解题思路和完全背包几乎一样,仅仅在递推公式有所区别
dp[i][j] = Math.max(dp[i - 1][j - n * w[i]] + n * v[i]) // (0 =< n <= j / w[i]) 且 (n <= k[i]) n为整数
总结
动态规划的三种背包类型,01背包,多重背包,完全背包就已经结束了。后面我们将学习动态规划的另一类问题:公共子串。