问题分析子问题界定:由参数 k 和 y 界定k:考虑对物品1, 2, … , k 的选择
y:背包总重量不超过 y
原始输入:k = n, y = b
子问题计算顺序: k = 1, 2, … , n
对于给定的 k,y = 1, 2, … , b
定义问题
假设有 n 个物品和一个最大承重为 W 的背包。每个物品 𝑖i 有一定的重量 wi 和价值 vi。我们的目标是选择一些物品装入背包,使得总重量不超过 W,且总价值最大。
动态规划数组定义
定义一个二维数组 dp,其中 dp[i][j] 表示从前 𝑖i 个物品中选取一些,使得总重量不超过 j 时的最大价值。
初始条件
初始化 𝑑𝑝[0][𝑗]=0对所有 j 成立,因为没有物品时,无论背包容量如何,可装入的最大价值都是 0。
转移方程
对于每个物品 i 和每种背包容量 j:
如果不选择物品 i:则 dp[i][j]=dp[i−1][j]
如果选择物品 i(前提是 𝑗≥𝑤i):则 dp[i][j]=max(dp[i−1][j],dp[i−1][j−wi]+vi)
dp[i][j]=max(dp[i−1][j],dp[i−1][j−wi]+vi)
这个方程的含义可以这样理解:
- dp[i−1][j]: 这部分表示如果我们不选择当前的物品 i,则问题就退化为“从前i−1 个物品中选择,背包容量为 j 的情况”。在这种情况下,我们已经在上一个状态计算出了不包括物品 i 时的最大价值。
- dp[i−1][j−wi]+vi: 这部分表示如果我们选择了当前的物品 i,则背包剩余的容量将减少 wi(物品 i 的重量),因此我们需要考虑的子问题变为“从前 i−1 个物品中选择,背包容量为 j−wi 的情况”。由于我们选择了物品 i,我们必须在此基础上加上物品 i 的价值 vi。
def knapsack(n, b, v, w):
'''
:param n: 物品有n种
:param b: 背包容量
:param v: 物品价值
:param w: 物品重量
:return: 最大价值
'''
# 初始化
V = [[0 for _ in range(b + 1)] for _ in range(n + 1)] # V[i][j] 表示前i个物