背包问题
0/1 背包问题
给定 N
件物品,每件物品有 重量 w[i] 和 价值 v[i],现有一个容量为 W
的背包,求能装入的最大总价值。
思路
-
定义状态
dp[i][j]
表示前i
件物品,在容量j
的背包下的最大价值。
-
状态转移方程
- 不选第 i 件物品:
dp[i][j] = dp[i-1][j]
- 选第 i 件物品(前提是能放得下):
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i])
- 不选第 i 件物品:
-
初始化
dp[0][j] = 0
(背包容量为j
,但没有物品)dp[i][0] = 0
(有物品,但背包容量为0
)
-
优化
- 使用 滚动数组 降低空间复杂度,从
dp[i][j]
改为dp[j]
,逆序遍历j
以保证状态不被覆盖。 -
-
0/1 背包问题的递归解法(C#)
递归方法是一种 自顶向下(Top-Down) 的方式来解决 0/1 背包问题,适合理解 子问题拆解 的思想。但由于存在大量重复计算,需要使用 记忆化搜索(Memoization) 来优化效率。
递归思路
-
定义递归函数:
KnapsackRecursive(n, capacity)
表示前n
个物品在总容量capacity
下的最大价值。
-
状态转移方程:
- 如果不选当前物品:
KnapsackRecursive(n - 1, capacity)
- 如果选当前物品(前提是容量足够): KnapsackRecursive(n−1,capacity−weights[n−1])+values[n−1]KnapsackRecursive(n - 1, capacity - weights[n-1]) + values[n-1]KnapsackRecursive(n−1,capacity−weights[n−1])+values[n−1]
- 取两者的最大值: dp[n,capacity]=max(KnapsackRecursive(n−1,capacity),KnapsackRecursive(n−1,capacity−weights[n−1])+values[n−1])dp[n, capacity] = \max(KnapsackRecursive(n - 1, capacity), KnapsackRecursive(n - 1, capacity - weights[n-1]) + values[n-1])dp[n,capacity]=max(KnapsackRecursive(n−1,capacity),KnapsackRecursive(n−1,capacity−weights[n−1])+values[n−1])
- 如果不选当前物品:
-
终止条件:
- 当
n == 0
或capacity == 0
时,返回0
(没有物品或容量为 0)。
- 当
-
优化:记忆化搜索
- 使用
memo[n, capacity]
记录已经计算过的结果,避免重复计算,提高效率。
- 使用
-
-
-
- 使用 滚动数组 降低空间复杂度,从