02_Knapsack DP 背包DP

背包 DP

背包问题简介

背包问题通常涉及将有限容量的容器用物品的子集填满,我们希望计算或优化与物品相关的某些数量。几乎每次,你可以将每个物品视为具有正重量,而我们选择的物品的总重量不得超过容器的容量,这个容量是一个数字。

背包问题的变体

  • 0/1 背包问题: 选择物品的子集,使得它们总价值最大化,且总重量不超过容器容量
  • 完全背包问题: 找到所有可能的、由任何物品子集实现的总重量,这些总重量不超过容器容量
  • 计数问题: 计算有多少种物品序列能够完全填满容器,这意味着总重量正好等于容器的容量(顺序可能重要也可能不重要)

提示: 背包问题的动态规划解法通常包含一个状态来跟踪背包的容量,状态转移涉及尝试将一个物品添加到背包中。在竞赛编程中,你可以预期经典背包问题会被赋予变化、伪装和额外的状态信息。


多重背包问题

问题描述

N 种物品,每种物品有重量 wi、价值 vi 和数量 ci,求在不超过背包容量 W 的情况下,选择物品使得总价值最大。

解法

定义dp[j] 为背包容量为 j 时的最大价值

初始条件dp[j] = 0

状态转移:将数量 ci 拆分成 1, 2, 4, 8, … 的物品件数,转化为 0/1 背包问题

dp[j] = max (dp[j], dp[j − w] + v)

代码实现

# 多重背包 - 二进制优化
N, W = map(int, input().split())
items = []

for _ in range(N):
    w, v, c = map(int, input().split())
    k = 1
    while c > 0:
        take = min(k, c)
        items.append((w * take, v * take))
        c -= take
        k *= 2

dp = [0] * (W + 1)
for w, v in items:
    for j in range(W, w - 1, -1):
        dp[j] = max(dp[j], dp[j - w] + v)

print(dp[W])

时间复杂度:O(N × log(c_i) × W) 空间复杂度:O(W)


总结

问题类型 状态转移 内层循环方向
0/01 背包 dp[j] = max (dp[j], dp[j − w] + v) 倒序
完全背包 dp[j] = max (dp[j], dp[j − w] + v) 正序
多重背包 二进制优化转为 0/01 背包 倒序

02_Knapsack DP 背包DP
https://mingsm17518.github.io/2026/04/08/algorithm/03_Gold/02_动态规划/02_Knapsack DP 背包DP/
作者
Ming
发布于
2026年4月8日
更新于
2026年4月8日
许可协议