跳转到内容

多重背包问题

来自代码酷

模板:Note

多重背包问题[编辑 | 编辑源代码]

多重背包问题(Multiple Knapsack Problem)是背包问题的扩展形式之一,其特点是每种物品有固定的数量限制(既不是无限取用的完全背包,也不是只能取0或1次的01背包)。该问题在资源分配、生产调度等领域有广泛应用。

问题定义[编辑 | 编辑源代码]

给定:

  • 背包容量 W
  • n 种物品,每种物品有三个属性:
 * 重量 wi
 * 价值 vi
 * 最大可用数量 si

目标:选择物品装入背包,使得总重量不超过 W 且总价值最大。

数学表达[编辑 | 编辑源代码]

{最大化i=1nvixi约束条件i=1nwixiW0xisi(xi)

基本解法[编辑 | 编辑源代码]

动态规划思路[编辑 | 编辑源代码]

使用二维状态数组 dp[i][j] 表示前 i 种物品在背包容量为 j 时的最大价值。

状态转移方程: dp[i][j]=max{dp[i1][j],dp[i1][jkwi]+kvi(1kmin(si,j/wi))

代码实现[编辑 | 编辑源代码]

def multiple_knapsack(W, weights, values, counts):
    n = len(weights)
    dp = [[0] * (W + 1) for _ in range(n + 1)]
    
    for i in range(1, n + 1):
        for j in range(W + 1):
            max_k = min(counts[i-1], j // weights[i-1])
            dp[i][j] = max(
                dp[i-1][j - k * weights[i-1]] + k * values[i-1]
                for k in range(0, max_k + 1)
            )
    
    return dp[n][W]

# 示例
W = 10
weights = [2, 3, 4]
values = [3, 4, 5]
counts = [3, 2, 1]
print(multiple_knapsack(W, weights, values, counts))  # 输出:13

优化方法[编辑 | 编辑源代码]

二进制拆分优化[编辑 | 编辑源代码]

将每种物品的数量 si 拆分为 1,2,4,...,2k1,si2k+1 的组合,转化为01背包问题。

示例:

  • 某物品有13件 → 拆分为1, 2, 4, 6四个"新物品"
  • 时间复杂度从 O(nWS) 降为 O(nWlogS)

空间优化[编辑 | 编辑源代码]

使用滚动数组将空间复杂度从 O(nW) 降为 O(W)

def optimized_multiple_knapsack(W, weights, values, counts):
    dp = [0] * (W + 1)
    
    for i in range(len(weights)):
        # 二进制拆分
        k = 1
        remaining = counts[i]
        while k <= remaining:
            w = k * weights[i]
            v = k * values[i]
            for j in range(W, w - 1, -1):
                dp[j] = max(dp[j], dp[j - w] + v)
            remaining -= k
            k *= 2
        if remaining > 0:
            w = remaining * weights[i]
            v = remaining * values[i]
            for j in range(W, w - 1, -1):
                dp[j] = max(dp[j], dp[j - w] + v)
    
    return dp[W]

实际应用案例[编辑 | 编辑源代码]

物流装箱问题

  • 有若干种货物(每种有固定数量)
  • 卡车有最大载重限制
  • 需要选择货物组合使运输价值最大化

graph TD A[货物A: 重量2,价值3,数量3] -->|选择2件| B(总重量4,价值6) C[货物B: 重量3,价值4,数量2] -->|选择1件| D(总重量7,价值10) E[货物C: 重量4,价值5,数量1] -->|选择0件| F(最终组合)

复杂度分析[编辑 | 编辑源代码]

方法 时间复杂度 空间复杂度
基本动态规划 O(nWS) O(nW)
二进制优化 O(nWlogS) O(W)

常见问题[编辑 | 编辑源代码]

模板:Q&A

扩展练习[编辑 | 编辑源代码]

1. 修改代码处理重量为小数的情况
2. 实现输出具体选取方案的功能
3. 研究存在「物品依赖性」时的变种问题

模板:Algorithm-stub