个人主页:丷从心
系列专栏:回溯法
max ∑ i = 1 n v i x i { ∑ i = 1 n w i x i ≤ c x i ∈ { 0 , 1 } ( 1 ≤ i ≤ n ) \max\displaystyle\sum\limits_{i = 1}^{n}{v_{i} x_{i}} \kern{2em} \begin{cases} \displaystyle\sum\limits_{i = 1}^{n}{w_{i} x_{i} \leq c} \\ x_{i} \in \set{0 , 1} (1 \leq i \leq n) \end{cases} maxi=1∑nvixi⎩ ⎨ ⎧i=1∑nwixi≤cxi∈{0,1}(1≤i≤n)
Python
实现def backtrack_knapsack(values, weights, capacity):
n = len(values)
# 计算物品的单位重量价值
unit_values = [v / w for v, w in zip(values, weights)]
# 根据单位重量价值对物品进行降序排序
sorted_items = sorted(range(n), key=lambda k: unit_values[k], reverse=True)
best_solution = []
best_value = 0
def constraint(weight):
# 约束函数: 检查当前解是否满足容量限制
return weight <= capacity
def bound(weight, value, index):
# 限界函数: 计算当前解的价值总和加上剩余物品价值作为上界, 用于剪枝
bound = value
remaining_capacity = capacity - weight
for item in range(index + 1, n):
if remaining_capacity >= weights[sorted_items[item]]:
remaining_capacity -= weights[sorted_items[item]]
bound += values[sorted_items[item]]
else:
bound += remaining_capacity * values[sorted_items[item]] / weights[sorted_items[item]]
break
return bound
def backtrack(solution, weight, value, index):
nonlocal best_solution, best_value
if index == n:
# 已经遍历完所有物品
if value > best_value:
# 如果当前解的价值更大, 更新最优解
best_solution = solution
best_value = value
return
# 尝试选择当前物品
weight += weights[sorted_items[index]]
value += values[sorted_items[index]]
if constraint(weight):
# 如果满足约束函数, 继续探索下一个物品
backtrack(solution + [1], weight, value, index + 1)
# 恢复回溯之前状态
weight -= weights[sorted_items[index]]
value -= values[sorted_items[index]]
# 尝试不选择当前物品
if bound(weight, value, index) >= best_value:
# 如果当前解的上界仍然可能更好, 继续探索下一个物品
backtrack(solution + [0], weight, value, index + 1)
backtrack([], 0, 0, 0)
return best_solution, best_value
values = [60, 100, 120]
weights = [10, 20, 30]
capacity = 50
best_solution, best_value = backtrack_knapsack(values, weights, capacity)
print(f'最优解: {best_solution}')
print(f'最优值: {best_value}')
最优解: [0, 1, 1]
最优值: 220