You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
49 lines
2.3 KiB
49 lines
2.3 KiB
# work1. 01背包问题
|
|
# 设 dp[i][w] 表示在背包容量为 w 时,前 i 个物品能够达到的最大总价值。
|
|
# 状态转移方程:
|
|
# 对于第 i 个物品,存在两种情况:
|
|
# 如果第 i 个物品的重量大于当前背包容量 w,则无法放入背包,此时 dp[i][w] 等于 dp[i-1][w],即不放入该物品。
|
|
# 如果第 i 个物品的重量小于等于当前背包容量 w,则考虑放入或不放入背包两种情况,取其中价值更大的情况。
|
|
# 如果放入第 i 个物品,则总价值为 values[i] + dp[i-1][w-weights[i]]。
|
|
# 如果不放入第 i 个物品,则总价值为 dp[i-1][w]。
|
|
# 综合考虑以上两种情况,dp[i][w] 的值为这两种情况中的较大值。
|
|
# 初始化:
|
|
# 当没有物品可选时,背包能够达到的最大总价值为0,即 dp[0][w] = 0,其中 w 取值为0到背包容量 capacity。
|
|
# 填充数组:
|
|
# 使用两层循环填充 dp 数组,外层循环遍历物品,内层循环遍历背包容量,根据状态转移方程更新 dp[i][w] 的值。
|
|
# 回溯:
|
|
# 根据 dp 数组中存储的最优解,找出放入的是哪些物品。
|
|
# 返回结果:
|
|
def knapsack(weights: list[int], values: list[int], capacity: int) -> int:
|
|
n = len(weights)
|
|
# 创建一个二维数组来存储子问题的解
|
|
dp = [[0] * (capacity + 1) for _ in range(n + 1)]
|
|
|
|
# 填充dp数组
|
|
for i in range(1, n + 1):
|
|
for w in range(1, capacity + 1):
|
|
# 如果当前物品的重量大于背包容量,则不能放入背包
|
|
if weights[i - 1] > w:
|
|
dp[i][w] = dp[i - 1][w]
|
|
else:
|
|
# 考虑放入或不放入当前物品,选择其中价值更大的方案
|
|
dp[i][w] = max(dp[i - 1][w], values[i - 1] + dp[i - 1][w - weights[i - 1]])
|
|
|
|
# 找出放入背包的物品
|
|
selectedItems = []
|
|
i, w = n, capacity
|
|
while i > 0 and w > 0:
|
|
if dp[i][w] != dp[i - 1][w]:
|
|
selectedItems.append(i - 1)
|
|
w -= weights[i - 1]
|
|
i -= 1
|
|
|
|
return dp[n][capacity], selectedItems
|
|
|
|
# 测试
|
|
weights = [10, 20, 30, 40, 50]
|
|
values = [50, 120, 150, 210, 240]
|
|
capacity = 50
|
|
max_value, selected_items = knapsack(weights, values, capacity)
|
|
print("最大价值:", max_value)
|
|
print("选择的物品索引:", selected_items) |