算法——背包问题——0-1背包问题 python代码实现

0-1 背包问题(0-1 Knapsack Problem)

问题描述:给定 n 个物品,每个物品有重量 wi​ 和价值 vi​,以及一个容量为 W 的背包。每个物品只能选择 放入或不放入 背包,求如何选择物品使得总价值最大且总重量不超过 W。
特点:每个物品只能选择一次。
应用场景:资源分配、投资组合选择等。
解决的问题:在资源有限(背包容量有限)的情况下,对具有不同价值和重量的物品进行选择,以达到价值最大化的决策问题。例如,在一次旅行中,旅行者的背包容量有限,需要从各种不同重量和价值的物品中选择携带哪些物品,以在不超过背包容量的前提下,使携带物品的总价值最高。

代码实现

def knapsack(V, costs, values):
    n = len(costs)
    # dp[v] 表示容量为v时的最大价值`在这里插入代码片`
    dp = [0] * (V + 1)
    
    for i in range(n):
        # 逆序遍历容量,避免重复计算
        for v in range(V, costs[i] - 1, -1):
            # 选择当前物品或不选,取最大值
            dp[v] = max(dp[v], dp[v - costs[i]] + values[i])
    
    return dp[V]

使用示例

# 示例输入
V = 4  # 背包容量
costs = [3, 4, 1]  # 物品费用
values = [20, 30, 15]  # 物品价值

# 调用函数
max_value = knapsack(V, costs, values)
print("最大价值:", max_value)  # 输出: 35(选择第1和3号物品,总费用3+1=4,价值20+15=35)

关键解释

  1. 动态规划状态定义
    dp[v] 表示背包容量为 v 时的最大价值。通过逐步考虑每个物品,更新不同容量下的最优解。

  2. 逆序遍历容量的原因
    正序遍历会导致同一物品被多次选择(即变成完全背包问题),而逆序保证每个物品只被计算一次。

  3. 时间复杂度
    ( O(N \times V) ),其中 ( N ) 为物品数量,( V ) 为背包容量。


其他测试案例

案例 1

V = 5
costs = [2, 3, 4, 5]
values = [3, 4, 5, 6]
# 最大价值为7(选择物品0和1,费用2+3=5,价值3+4=7)
print(knapsack(V, costs, values))  # 输出: 7

案例 2

V = 10
costs = [5, 4, 6, 3]
values = [10, 40, 30, 50]
# 最大价值为90(选择物品1和3,费用4+3=7 ≤10,价值40+50=90)
print(knapsack(V, costs, values))  # 输出: 90

扩展:输出选择的物品列表

如果需要记录具体选择的物品,可以通过反向追踪 dp 数组实现:

def knapsack_with_items(V, costs, values):
    n = len(costs)
    dp = [0] * (V + 1)
    # 记录每个容量下的物品选择路径
    selected = [[] for _ in range(V + 1)]
    
    for i in range(n):
        for v in range(V, costs[i] - 1, -1):
            if dp[v - costs[i]] + values[i] > dp[v]:
                dp[v] = dp[v - costs[i]] + values[i]
                selected[v] = selected[v - costs[i]] + [i]  # 记录选择路径
    
    return dp[V], selected[V]

# 示例
max_val, items = knapsack_with_items(4, [3,4,1], [20,30,15])
print("最大价值:", max_val)   # 输出: 35
print("选择的物品索引:", items)  # 输出: [0, 2]

通过这种方式,可以同时获取最大价值和具体选择的物品。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值