备战蓝桥杯Day35 - 动态规划 - 01背包问题

本文介绍了如何使用动态规划解决01背包问题,通过状态表示将物品分类并确定目标属性(最大价值),然后通过状态计算确定在给定容量下选取物品的最大价值。作者详细解释了状态转移方程和代码实现的过程。
摘要由CSDN通过智能技术生成

问题描述

隐含前提:

1.物体是不可分的,要么装,要么不装,不能只装一部分。

2.物体顶多使用一次。

动态规划思路 

我在b站上看的闫氏dp分析大法的视频,他对dp问题做了总结归纳。

从集合的角度分析dp问题。求出有限集中的最值 / 个数。

分析内容主要包括两部分:

1.状态表示(化零为整):将一些有相似特征的元素化成一个子集,用某一个状态表示。

        1.1 明确集合分类

        1.2 明确题目中要找的属性(最大值 / 最小值 / 个数)

2.状态计算(化整为零):将数据划分为不同的子集。(依据:寻找最后一个不同点)

        2.1 数据不重复

        2.2 数据不遗漏

分析01背包问题

1.集合:

所有只考虑前 i 个物品,且总体积不超过 j 的选法的集合

2.属性:

集合中每个方案的最大值

3. 状态计算:

第一种:所有不选第 i 个物品的集合。

所以要从第1个到第 i - 1 中进行选择,且总体积不超过 j 。 dp[ i ][ j ] = dp[ i-1 ][ j ]

第二种:所以选了第 i 个物品的集合

我们已经选了第 i 个, 所以前 i-1个物品我们要选出最大值,且 前 i-1个物品的总体积为 j - vi。

dp[ i ][ j ] = dp[i-1][j - vi] + wi

这两种情况我们要取最大值。

所以最后状态计算表达式为:

dp[ i ][ j ] = max(dp[ i - 1][ j ], dp[i-1][j - vi] + wi)

代码实现

def knapsack_01(N, V, volumes, values):  
    # 初始化 dp 数组,dp[i][j] 表示考虑前 i 件物品,在容量为 j 的背包中能够得到的最大价值  
    dp = [[0 for _ in range(V + 1)] for _ in range(N + 1)]  
  
    # 动态规划过程  
    for i in range(1, N + 1):  
        for j in range(1, V + 1):  
            # 如果第 i 件物品的体积大于当前背包容量 j,则不能装入  
            if volumes[i - 1] > j:  
                dp[i][j] = dp[i - 1][j]  
            else:  
                # 否则考虑放入和不放入两种情况,取较大者  
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - volumes[i - 1]] + values[i - 1])  
  
    # 返回最大价值,即所有物品考虑在内,背包容量为 V 的最大价值  
    return dp[N][V]  
  
# 读取输入  
N, V = map(int, input().split())  
volumes = []  
values = []  
for _ in range(N):  
    v, w = map(int, input().split())  
    volumes.append(v)  
    values.append(w)  
  
# 输出最大价值  
print(knapsack_01(N, V, volumes, values))

读取输入这样写就很妙,学会了。一点一点的进步吧!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值