This commit is contained in:
krahets
2023-07-09 03:02:07 +08:00
parent 92a65e3af9
commit b1544c92ca
5 changed files with 622 additions and 28 deletions

View File

@@ -22,17 +22,15 @@ comments: true
我们可以将 0-1 背包问题看作是一个由 $n$ 轮决策组成的过程,每个物体都有不放入和放入两种决策,因此该问题是满足决策树模型的。此外,该问题的目标是求解“在限定背包容量下的最大价值”,因此较大概率是个动态规划问题。我们接下来尝试求解它。
**第一步:思考每轮的决策是什么,从而得到状态定义**
**第一步:思考每轮的决策,定义状态,从而得到 $dp$ 表**
在 0-1 背包问题中,不放入背包,背包容量不变;放入背包,背包容量减小。由此可得状态定义:物品编号 $i$ 和背包容量 $c$ ,记为 $[i, c]$ 。
在 0-1 背包问题中,不放入背包,背包容量不变;放入背包,背包容量减小。由此可得状态定义:当前物品编号 $i$ 和剩余背包容量 $c$ ,记为 $[i, c]$ 。
**第二步:明确子问题是什么,从而得到 $dp$ 列表**
状态 $[i, c]$ 对应的子问题为:**前 $i$ 个物品在容量为 $c$ 背包中的最大价值**,记为 $dp[i, c]$ 。
状态 $[i, c]$ 对应的子问题为:**前 $i$ 个物品在剩余容量为 $c$ 的背包中的最大价值**,记为 $dp[i, c]$ 。
至此,我们得到一个尺寸为 $n \times cap$ 的二维 $dp$ 矩阵。
**第步:找出最优子结构,进而推导出状态转移方程**
**第步:找出最优子结构,进而推导出状态转移方程**
当我们做出物品 $i$ 的决策后,剩余的是前 $i-1$ 个物品的决策。因此,状态转移分为两种情况:
@@ -47,6 +45,12 @@ $$
需要注意的是,若当前物品重量 $wgt[i - 1]$ 超出剩余背包容量 $c$ ,则只能选择不放入背包。
**第三步:确定边界条件和状态转移顺序**
当无物品或无剩余背包容量时最大价值为 $0$ ,即所有 $dp[i, 0]$ 和 $dp[0, c]$ 都等于 $0$ 。
当前状态 $[i, c]$ 从上方的状态 $[i-1, c]$ 和左上方的状态 $[i-1, c-wgt[i-1]]$ 转移而来,因此通过两层循环正序遍历整个 $dp$ 表即可。
## 13.4.1.   方法一:暴力搜索
搜索代码包含以下要素:
@@ -255,7 +259,7 @@ $$
def knapsack_dp(wgt, val, cap):
"""0-1 背包:动态规划"""
n = len(wgt)
# 初始化 dp
# 初始化 dp 表
dp = [[0] * (cap + 1) for _ in range(n + 1)]
# 状态转移
for i in range(1, n + 1):
@@ -405,7 +409,7 @@ $$
def knapsack_dp_comp(wgt, val, cap):
"""0-1 背包:状态压缩后的动态规划"""
n = len(wgt)
# 初始化 dp
# 初始化 dp 表
dp = [0] * (cap + 1)
# 状态转移
for i in range(1, n + 1):