动态规划之二:背包问题knapsack

本文介绍了背包问题的动态规划求解方法,包括递归、记忆化和直接数组法。通过分析问题定义目标函数,寻找状态转移公式,展示了如何在有限容量的背包中选取物品以获得最大价值总和。最终得出解决方案,并强调了数组法和记忆化在提高效率上的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背包问题描述

有n个物品,它们有各自的体积和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?

类似的问题非常多:
比如每个任务都有时间和价值,我们有一定的时间,现在在有限的的时间里完成最大价值的任务,如何安排?

任务 A B C D E F G
所得收益 7 9 5 12 14 6 12
需要时间 3 4 2 6 7 3 5

下面就以这个问题来进行分析。

分析

如果简单的用 收益/时间来表示收益率,其实非常容易解决这个问题,然而任务是无法分解的。不能做三分之一就停止。
我们还是用背包问题求解。

背包问题的核心是定义目标和找到状态转移公式。

求解

定义目标:求最大收益。
v[i][j] 来表示最大收益,背景:j是背包容量(时间),前i个物品的组合;
这个是关键定义。

然后我们找到相邻两步的关系(注意我们做任何事情都需要极度关注相邻状态,比如马尔科夫链)
v[i][j] 和上一个i-1个物品组合有何关系?
i物品太大,j放不下,那么 v[i][j]=v[i-1][j]
i物品可以放,那么 max(v[i-1][j], v[i-1][j-s[i]] + v[i])就是最优的。

这一步是第二个关键,我们分解一下。

  1. 放得下,那么放的话,则 v[i-1][j-s[i]]+v[i] 这就是放完的最优状态
  2. 放得下,但是不放, 收益其实不变,还是上一个状态的v[i-1][j]

那么再反过来思考一下:
v[i][j]是最优的
v[i-1][j-si]是最优的,空间变小后,收益增加v[i], 那么必须比较一下,到底是放进去带来的总体更好,还是不放留给后面的更好?

方法一: 递归

def value(n, space):
    '''
    knapsack递归解法
    选择第n个item的时候,到底是选择做还是不做;选择不做,空间不变,收益不变;
    如果选择做,那么space要减掉,收益增加v(n)
    :param n:
    :param space:
    :return:
    '''
    if n==0:
        return 0
    if item[n][1] >space:
        return value(n-1,space)
    return max(value(n-1,space), 
    value(n-1,space-item[n][1])+item[n][0])

方法二:递归记忆

方法三:直接数组

数组的方法也放在这里,总体代码如下,请忽略格式。

import 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值