基础背包问题

一、问题定义

背包问题是组合优化中的经典问题:

给定一个容量有限的背包和若干物品(每个物品有重量和价值),如何选择物品装入背包,使得总价值最大且不超过背包容量?

二、背包问题的分类

背包问题
├── 0/1 背包 → 每个物品最多选 1 次
├── 完全背包 → 每个物品可选无限次
├── 多重背包 → 每个物品有数量限制
├── 分组背包 → 物品分组,每组最多选一个
└── 混合背包 → 以上类型的组合

三、核心逻辑

由问题定义出发,该问题主要是由两个维度(容量[物品重量和]、价值)组成的优化问题,解决它的关键也是由这两个维度构建的状态转移方程,通过它求解(容量、最大价值)。
以基础的0/1背包为例,最直接的思路就是枚举(容量、价值)这个状态矩阵,根据状态转移方程更新这个矩阵。
其转移方程为:

对于第 i 个物品,只有两种选择:

① 不选第 i 个物品: dp[i][j] = dp[i-1][j]
② 选第 i 个物品:   dp[i][j] = dp[i-1][j-w[i]] + v[i]  (前提: j >= w[i])

dp[i][j] = max(不选, 选)

对于二维DP的话,这个方程就非常简单,顺序更新即可。直观理解就是遍历每个容量值,尝试放入物品并取最大价值。可视化该状态矩阵更新:

         容量j →  0   1   2   3   4   5   6   7   8   9  10
物品0(w=2,v=6)    0   0   6   6   6   6   6   6   6   6   6
物品1(w=5,v=12)   0   0   6   6   6  12  12  18  18  18  18
物品2(w=4,v=8)    0   0   6   6   8  12  14  18  18  20  20
物品3(w=7,v=15)   0   0   6   6   8  12  14  18  18  21  21
                                                          ↑
                                                       答案=21? 
实际 dp[4][10] = max(21, ...) 需要重新验证 → 答案是 21

可以看到二维状态矩阵是有一部分信息冗余的,冗余的部分就是保存了枚举到的每个物品对应的中间价值,我们只关心最终所有物品都遍历后的结果。这就产生了一维DP的空间优化:
使用一维数组保存 每个容量 对应的最大价值 (\(f(volume) \rightarrow Worth_{max}\)) ,枚举容量的时候需要逆序,因为转移方程是依赖前序容量的value的,二维DP将该值按物品隔离了,一维是压缩在一起,因此只能逆序更新。

def knapsack_01_optimized(W, weights, values):
    n = len(weights)
    dp = [0] * (W + 1)

    for i in range(n):
        # ⭐ 必须逆序遍历,防止同一物品被重复选取
        for j in range(W, weights[i] - 1, -1):
            dp[j] = max(dp[j], dp[j - weights[i]] + values[i])

    return dp[W]

四、完全背包

完全背包的关键就是每个物品可以重复选,上面也提示到了核心区别,在0/1背包中,枚举当前物品时,只能从上一个物品的状态进行更新,而一维优化时,需要逆序来避免重复选择。因此完全背包的唯一区别就是可以从 当前物品 的状态进行更新(当前物品可重复用),并且一维DP时直接正序更新就可以。

def knapsack_01_optimized(W, weights, values):
    n = len(weights)
    dp = [0] * (W + 1)

    for i in range(n):
        # ⭐ 必须逆序遍历,防止同一物品被重复选取
        for j in range(weights[i], W + 1):
            dp[j] = max(dp[j], dp[j - weights[i]] + values[i])

    return dp[W]

拓展

对于其他如多重背包,每种物品有上限,就是多一个限制条件,对于每种物品的容量来说,就是多枚举一轮物品个数即可。

变种

还有其他问题不只是求解最大value,也有求最大方案数的。

posted @ 2026-04-15 20:32  breezezz  阅读(30)  评论(0)    收藏  举报