背包问题概述
背包问题是动态规划的一类经典问题。其本质是一种组合优化的 NP 完全问题。问题描述为:给定一组物品,每种物品都有自己的重量和价值,在限定的总重量内,如何选择才能使物品的总价值最高。
根据物品个数限制,背包问题分为以下几类:
- 01 背包问题:每个物品只有一个
- 完全背包问题:每个物品有无限多个
- 多重背包问题:每件物品有有限个
- 混合背包问题:包含上述三种情况
- 分组背包问题:物品分 n 组,每组最多选一个
此外,根据背包是否装满可分为'不一定装满'和'一定装满';根据限定条件个数可分为'普通背包'和'二维费用背包'。
尽管分类繁多,大多是从 01 背包演化而来,因此掌握 01 背包至关重要。背包问题的优化通常涉及空间复杂度的降低,常见方案包括滚动数组优化。
01 背包(medium)
题目描述:
你有一个背包,最多能容纳的体积是 V。现在有 n 个物品,第 i 个物品的体积为 vi,价值为 wi。
- 求这个背包至多能装多大价值的物品?
- 若背包恰好装满,求至多能装多大价值的物品?
输入描述:
第一行两个整数 n 和 V。接下来 n 行,每行两个数 vi 和 wi。
其中 1 ≤ n, V, vi, wi ≤ 1000。
输出描述: 输出两行,第一行为第一问答案,第二行为第二问答案(无解输出 0)。
1、第一问解题思路
背包问题的本质是动态规划。按照五部曲解析:
状态表示
定义 dp[i][j] 表示从前 i 个物品中选择,且物品总体积不超过 j 时,能装入背包的最大物品价值。
状态转移方程
对于第 i 个物品,有两种选择:
- 不选:
dp[i][j] = dp[i - 1][j] - 选(需满足
j >= v[i]):dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i])
初始化
虚拟行列初始化为 0。dp[0][j] 表示无物品,价值为 0;dp[i][0] 表示背包容量为 0,价值为 0。
遍历顺序
从上往下,从左往右遍历。
返回值
返回 dp[n][V]。
2、第二问解题思路
第二问要求背包恰好装满,需在第一问基础上修改细节。
状态表示修改
dp[i][j] 表示从前 i 个物品中选择,且物品总体积正好等于背包空间 j 时的最大价值。
状态转移方程细节修改
判断 dp[i - 1][j - v[i]] 是否能构成 j - v[i] 的空间。设定 dp[i][j] == -1 表示无法凑成对应体积,非 -1 则为最大价值。


