一、01背包
概念:
给你一个容量为C的背包,有n个物品。每个物体都有两个属性,即重量(w)和价值(v)。如果背包剩余容量大于此物品的重量,即可放入,同时产生这个物品的价值。
问:如何将物体放入背包才能使放入物体的总价值最大,同时输出这个值?
为何不用贪心?
证明:
看到这个问题,你可能会想到使用贪心,我来反驳一下:
01 背包中,物品只能完整选择,选择某物品会占用背包空间,可能导致无法选择其他更有价值的物品组合。此时,贪心算法的 “局部最优”可能会排斥掉更优的全局组合。
举个反例:
背包最大承重为5,有3个物品,物品如下:
| 物品 | 重量 | 价值 | 性价比(≈) |
|---|---|---|---|
| A | 4 | 5 | 1.25 |
| B | 3 | 4 | 1.33 |
| C | 3 | 4 | 1.33 |
贪心(按单位价值排序): 先选择 B 或 C,无法容纳其他物品,总价值是4。
最优解:选择A,总价值为5。
科普:
有一种背包叫做分数背包问题,可以把某一种物品分割放入背包中,这时你就可以利用这种贪心方法。
dp做法:
1. 状态定义
设 dp[i][j] 表示:考虑前 i 个物品(编号从 1 到 i),且背包承重上限为 j 时,能获得的最大总价值。
- 其中,
i的范围是0 ≤ i ≤ n(i=0表示无物品); j的范围是0 ≤ j ≤ C(j=0表示背包承重为 0)。
2. 初始化
- 当
i=0(无物品)时,无论背包承重j多大,总价值均为 0,即dp[0][j] = 0(0 ≤ j ≤ C)。 - 当
j=0(背包承重为 0)时,无论考虑多少物品,总价值均为 0,即dp[i][0] = 0(0 ≤ i ≤ n)。
3. 转移方程
对于第 i 个物品(重量 w[i],价值 v[i]),有两种选择:
- 不放入:此时总价值与 “考虑前
i-1个物品、承重j” 的情况相同,即dp[i][j] = dp[i-1][j]。 - 放入(需满足
j ≥ w[i]):此时总价值为 “前i-1个物品在承重j - w[i]时的最大价值” 加上当前物品的价值,即dp[i][j] = dp[i-1][j - w[i]] + v[i]。
因此,转移方程为:
if (j < w[i]) dp[i][j] = dp[i-1][j];
else dp[i][j] = max(dp[i-1][j], dp[i-1][j - w[i]] + v[i]);
4. 最终答案
考虑所有 n 个物品,且背包承重为 C 时的最大价值,即 dp[n][C]。
5. 时间复杂度与空间复杂度
- 时间复杂度:
O(n*C),其中n是物品数量,C是背包最大承重。需遍历n*C个状态,每个状态的计算为O(1)。 - 空间复杂度:
- 原始二维数组:
O(n*C)(存储n+1行、C+1列的状态)。
- 原始二维数组:
3477

被折叠的 条评论
为什么被折叠?



