mirror of
https://github.com/krahets/hello-algo.git
synced 2026-04-05 03:30:30 +08:00
build
This commit is contained in:
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user