背包算法(Knapsack Problem)是经典的优化问题,分为0-1背包和分数背包。以下通过Python实现0-1背包的动态规划解法,并结合实际案例说明。
问题描述
给定一组物品,每个物品有重量weight和价值value,在背包容量限制W下,如何选择物品使总价值最大且不超过背包容量。
动态规划解法
动态规划的核心是构建一个二维数组dp,其中dp[i][j]表示前i个物品在容量j下的最大价值。
def knapsack(weights, values, W):
n = len(values)
dp = [[0 for _ in range(W + 1)] for _ in range(n + 1)]
for i in range(1, n + 1):
for w in range(1, W + 1):
if weights[i - 1] <= w:
dp[i][w] = max(dp[i - 1][w], values[i - 1] + dp[i - 1][w - weights[i - 1]])
else:
dp[i][w] = dp[i - 1][w]
return dp[n][W]
代码解释
- 初始化
dp表,行数为物品数+1,列数为背包容量+1。 - 遍历每个物品和每种容量,若当前物品重量小于等于容量,则选择放入或不放入的较大值。
- 最终
dp[n][W]即为最大价值。
实际案例
假设背包容量W=10,物品信息如下:
| 物品 | 重量 | 价值 |
|---|---|---|
| 1 | 2 | 6 |
| 2 | 2 | 10 |
| 3 | 3 | 12 |
调用函数:
weights = [2, 2, 3]
values = [6, 10, 12]
W = 10
print(knapsack(weights, values, W)) # 输出22
优化空间复杂度
可将二维数组优化为一维数组,节省空间:
def knapsack_optimized(weights, values, W):
n = len(values)
dp = [0] * (W + 1)
for i in range(n):
for w in range(W, weights[i] - 1, -1):
dp[w] = max(dp[w], values[i] + dp[w - weights[i]])
return dp[W]
输出所选物品
记录物品选择情况:
def knapsack_with_items(weights, values, W):
n = len(values)
dp = [[0] * (W + 1) for _ in range(n + 1)]
selected = [[] for _ in range(W + 1)]
for i in range(1, n + 1):
for w in range(1, W + 1):
if weights[i - 1] <= w and dp[i - 1][w - weights[i - 1]] + values[i - 1] > dp[i - 1][w]:
dp[i][w] = dp[i - 1][w - weights[i - 1]] + values[i - 1]
selected[w] = selected[w - weights[i - 1]] + [i - 1]
else:
dp[i][w] = dp[i - 1][w]
selected[w] = selected[w]
return dp[n][W], selected[W]
max_value, items = knapsack_with_items(weights, values, W)
print(f"最大价值: {max_value}, 所选物品索引: {items}") # 输出22和[1, 2]
复杂度分析
- 时间复杂度:O(nW),n为物品数量,W为背包容量。
- 空间复杂度:基础解法O(nW),优化后O(W)。
应用场景
- 资源分配问题(如广告投放预算优化)。
- 行程规划(选择景点最大化体验)。
- 金融投资组合优化。
通过调整输入参数,该算法可灵活应用于各类实际场景。
Python实现0-1背包算法
1220

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



