代码随想录算法训练营第四十五天(动态规划篇)|01背包

01背包理论基础

学习资料:代码随想录 (programmercarl.com)

 相关链接:题目页面 (kamacoder.com)

背包题目分类

01背包定义

有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。

解法

暴力解法

每种物品有两种状态:取或不取,因此可以用回溯法搜索出所有组合,选出价值最大的方案,时间复杂度为o(2^n)。

动态规划

举例:背包重量为4,物品为:

1. dp[i][j]定义

当前背包容量为j时, 从下标为[0, i]的物体中任意取,放到背包中,的最大价值。

    示意图如下:

   

2.递推公式

dp[i][j]可以从两个方向得到:

  • 放物品i: 由dp[i - 1][j - weight[i]]推出,即不放物品i时,容量为[j - weight[i]的背包(要给物品i流出放的重量)时的最大价值加上物品i的价值。
  • 不放物品i:由dp[i-1][j]推出,即容量为j,不放物品i时的最大价值。

递推公式为: dp[i][j] = max(dp[i-1][j], dp[i-1][j - weight[i]] + value[j])

3. 初始条件
  • 当背包容量为0时,那么不管从哪几个物体中选,最大价值总为0.
  • 当i为0时,即只能选择放入物品0或不放入物品0,想得到最大价值,肯定选择物品0最好, 但如果物品0重量大于背包容量时就无法放入,最大价值为0。
4. 遍历顺序

dp[i][j]由[i][j]位置的上方或者左上方得到,可以先遍历物品,也可以先遍历容量,我选择前者。具体步骤如下:

首先从dp[1][1]开始计算,当前物品1的重量(3)超过了背包总容量(1),所以无论之前的物品(这里指物品0)有没有放入背包,物品1都不可能放进去,所以背包的最大价值和在当前容量下放入物品1前的最大价值相同,即dp[1][1] = dp[0][1] = 15。dp[1][2]同理。

当背包扩容到3(即j = 3)时,直观来看,我们可以选择放入物品1,如果放入,就不能同时放入物品0,那么价值为20,如果不放物品1,可能的最大价值为只放物品0的价值,即15,因为20>15, 所以dp[1][3] = 20。把上述想法抽象总结如下:

容量大于物品1的容量,说明可以放入物品1。如果放入物品1,那留给前面的物体(这里指物品0)的容量只有j-wright[j](这里为0),所以前面物体能创造的最大价值为dp[i-1][j-weight[j]], 加上物品j后的价值为dp[i - 1][j - weight[j]] + value[i], 如果不放入物品1,那就和之前的情况一样,即dp[i-1][j]。取这两种情况价值大的,即max(dp[i - 1][j - weight[j]] + value[i], dp[i-1][j])。

5. 举例推导dp数组

在纸上举例,能写出下面的数组。

代码实现

在ACM模式下,Python的输入模式基础语句为下:

# 读取一个整数
n = int(input()) 

# 一行里有n个整数, 表示数据
a = list(map(int, input(),split()))

# 一行里面有两个整数
n, m = map(int, input().split()) 

# 如果有多行数据,则按照每行的顺序依次执行上述对应指令

objNum, bagWeight = map(int, input().split())

weight = [int(i) for i in input().split()]
value = [int(i) for i in input().split()]

dp = [[0]*(bagWeight+1) for i in range(objNum)]
for j in range(bagWeight+1):
    if j >= weight[0]:
        dp[0][j] = value[0]

for i in range(1, objNum): # 遍历
    for j in range(1, bagWeight+1):
        if weight[i] > j:
            dp[i][j] = dp[i-1][j]
        else:
            dp[i][j] = max(dp[i-1][j], dp[i-1][j - weight[i]] + value[i])
            
print(dp[objNum - 1][bagWeight])

  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值