Python背包算法案例详解

Python实现0-1背包算法

背包算法(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]

代码解释
  1. 初始化dp表,行数为物品数+1,列数为背包容量+1
  2. 遍历每个物品和每种容量,若当前物品重量小于等于容量,则选择放入或不放入的较大值。
  3. 最终dp[n][W]即为最大价值。
实际案例

假设背包容量W=10,物品信息如下:

物品重量价值
126
2210
3312

调用函数:

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)。
应用场景
  • 资源分配问题(如广告投放预算优化)。
  • 行程规划(选择景点最大化体验)。
  • 金融投资组合优化。

通过调整输入参数,该算法可灵活应用于各类实际场景。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

std7879

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值