动态规划:01 背包问题详解
问题概述
背包问题是动态规划中经典的组合优化模型,属于 NP 完全问题。其核心在于:给定一组物品,每种物品都有重量和价值,在限定的总重量内,如何选择才能使总价值最高。
根据物品数量限制,主要分为以下几类:
- 01 背包:每个物品只有一个。
- 完全背包:每个物品有无限多个。
- 多重背包:每件物品有有限个(s_i)。
- 混合背包:包含上述多种情况。
- 分组背包:物品分 n 组,每组最多选一个。
此外,根据是否要求装满、限定条件个数及输出目标的不同,问题会有更多变体。尽管分类繁多,但大多数都源于 01 背包的变种,因此掌握 01 背包是学习的关键。
题目描述
DP41【模板】01 背包
有一个容量为 V 的背包,现有 n 个物品,第 i 个物品的体积为 vi,价值为 wi。
- 求背包至多能装多大价值的物品?
- 若背包必须恰好装满,求至多能装多大价值的物品?
输入格式:
第一行两个整数 n 和 V。
接下来 n 行,每行两个数 vi 和 wi。
其中 1 ≤ n, V, vi, wi ≤ 1000。
输出格式: 两行,分别对应上述两个问题的答案。若无解则输出 0。
解题思路
第一问:最大价值
状态定义
我们需要记录当前考虑的物品数量和当前背包的剩余容量。定义 dp[i][j] 表示从前 i 个物品中选择,且总体积不超过 j 时,能获得的最大价值。
状态转移
对于第 i 个物品,有两种选择:
- 不选:价值等于前
i-1个物品在容量j下的最大价值,即dp[i-1][j]。 - 选:前提是
j >= v[i]。价值等于前i-1个物品在容量j - v[i]下的最大价值加上当前物品价值,即dp[i-1][j - v[i]] + w[i]。
取两者最大值:
dp[i][j] = max(dp[i-1][j], dp[i-1][j - v[i]] + w[i])
初始化与遍历
- 初始化:
dp[0][j]和dp[i][0]均为 0,表示没有物品或容量为 0 时价值为 0。 - 遍历顺序:从上到下,从左到右。
- 返回值:
dp[n][V]。
第二问:恰好装满
状态修改
状态定义不变,但含义变为'总体积正好等于 j'。
转移细节
如果选择第 i 个物品,需要确保 dp[i-1][j - v[i]] 本身是可达的(即能凑出该体积)。否则,强行加入会导致体积不等于 。
为了标记不可达状态,我们将 数组初始化为 ,表示无法凑出对应体积。只有当 时,才进行更新。


