首页 > 其他分享 >Day35 动态规划Part3

Day35 动态规划Part3

时间:2024-08-20 13:51:01浏览次数:13  
标签:背包 weight bagweight 重量 Day35 Part3 物品 动态 dp

目录

任务

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

01背包(KAMA46)

DP思路

dp[i][j] 为[0,i]的所有物品选取或不选取(在满足重量不超过重量的情况下)在重量j下的可获取的最大价值
不选第i个物品的价值为:dp[i-1][j]
选择第i个物品的价值为:dp[i-1][j-weight[i]]+value[i]
所以递推公式为 dp[i][j] = max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]

# 01背包
n, bagweight = map(int, input().split()) # 物品个数,背包重量
 
weight = list(map(int, input().split())) # 物品重量
value = list(map(int, input().split()))  #物品价值
 
dp = [ [0]*(bagweight+1) for _ in range(n) ] # n行bagweight 列
 
# for j in range(bagweight+1):  # j表示重量
#     if weight[0] <= j: #可以放下
#         dp[0][j] = value[0]
 
for j in range(weight[0],bagweight+1):  # j表示重量
        dp[0][j] = value[0]
 
# for i in range(n): #不用,因为默认全部初始化为0了
#     dp[i][0] = 0
         
for i in range(1,n):
    for j in range(1,bagweight+1):
        if j-weight[i] < 0:
            dp[i][j] = dp[i-1][j]
        else:
            dp[i][j] = max(dp[i-1][j],dp[i-1][j-weight[i]] + value[i])  #[0,i]的所有物品在重量j下的可获取的最大价值
 
print(dp[n-1][bagweight])

滚动数组思路

即将上面的二维dp数组压缩为一维,关键是如何更新一位数组中的值 ==》 倒序更新,因为实际上只是压缩了空间,实际的思路还是二维的,只不过用一个数组更新,则必须从后往前,因为后面的值要用到前面上面的旧值,如果先更新前面的,就丢失了前面的旧值,从而在计算后面的值时产生错误。这个思路的关键在于不去想一维DP数组的含义,而是去想如何利用一维计算原本需要二维空间的问题

# 01 背包一维(滑动数组)
n, bagweight = map(int, input().split()) # 物品个数,背包重量
 
weight = list(map(int, input().split())) # 物品重量
value = list(map(int, input().split()))  #物品价值
 
dp = [0] * (bagweight+1)
for j in range(weight[0],bagweight+1):
    dp[j] = value[0]
 
for i in range(1,n):
    for j in range(bagweight,0,-1):
        if j-weight[i] >= 0:
            dp[j] =  max(dp[j],dp[j-weight[i]] + value[i]) 
print(dp[bagweight])

416. 分割等和子集

思路

本题还是很难想的.
抽象成背包问题,其中数组中的元素为每个数字多可选1次的物品,其质量和价值均为其值,而背包重量为所需要的target。因为dp[target]为背包在重量为target时的最大价值,当dp[target] == target时,说明找到了数字加起来等于target的元素。
0-1 背包问题求的是最大值,而子集求的是等于某个值,这两个不是一回事啊?但其实是一回事,物品的重量和物品的价值是一样的,所选物品的重量只能小于等于背包重量,因此所选物品的价值也只能小于等于背包的重量,所以求的是所选物品价值的最大值,当物品价值的最大值等于背包重量时,其实也就表示所选物品的重量等于背包价值,也就是找到了子集和等于目标值。
关键是理解dp[i] == i 时,装满重量为i的背包,因为dp[i]表示累计的最大价值,而i表示重量。又因为每个物品的重量等于价值,即我累计了多少价值就选了多少同等重量的物品,所以相等时表示选择某些物体装满背包。所以当dp[target]==target时,表示选择某些数字能够装满背包。

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        weight = nums
        value = nums
        n = len(nums)
        target = sum(nums) // 2
        if sum(nums) %2 == 1:return False
        bagweight = target
        
        dp = [0]* (bagweight + 1)
        
        
        for i in range(1,n):
            for j in range(bagweight,0,-1):
                if j-weight[i] >= 0:
                    dp[j] =  max(dp[j],dp[j-weight[i]] + value[i]) 
                    
        if dp[target] == target: return True
        return False

标签:背包,weight,bagweight,重量,Day35,Part3,物品,动态,dp
From: https://www.cnblogs.com/haohaoscnblogs/p/18369314

相关文章

  • 代码随想录day35 || 416 分割等和子集
    背包问题有n件物品和一个最多能背重量为w的背包。第i件物品的重量是weight[i],得到的价值是value[i]。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。//pake//// @Description:// @paramweights:物品i对应重量// @paramvalue:物品i对应价值// @......
  • pod数据持久化-pv与pvc资源及动态存储StorageClass
    一、pc与pvc的概念在传统的存储卷挂载,比如说nfs,它虽然能够实现我们大多数的生产场景,但是,耦合性比较高;举例:假设,我们要将集群从“阿里云”迁移到我们私有云服务器上,并改变存储卷挂在的类型,就无法实现,必须使用原有的存储卷类型;比如我们阿里云的存储卷是nfs,我们线下服务器的存储卷......
  • 权值线段树与动态开点线段树
    权值线段树(维护一段值域)用线段树维护桶实质上是维护一段值域中数字出现次数例:\(1,5,4,6,7,3,8,4,5,6\);根:\(1-8\);左儿子:\(1-4\);右儿子:\(5-8\);询问目前出现第\(k\)小数字从根节点出发,如果根节点权值\(>k\)则证明存在第\(k\)小;以此类推问:如果值域很大,线段树炸了怎......
  • 动态dp
    T1一共\(n\)颗糖果,第\(i\)颗的价值为\(a[i]\),你不能连着选两颗,请问你的选到的最大价值为多少显然有如下写法:设\(dp[i][0/1]\)表示选到了第\(i\)颗,第\(i\)颗选或不选显然有转移:\(dp[i][0]=max(dp[i-1][0],dp[i-1][1])\)\(dp[i][1]=max(dp[i-1][......
  • 动态规划:找出每个位置为止最长的有效障碍赛跑路线
    目录问题定义思路解题过程复杂度code问题定义        你打算构建一些障碍赛跑路线。给你一个 下标从0开始 的整数数组 obstacles ,数组长度为 n ,其中 obstacles[i] 表示第 i 个障碍的高度。对于每个介于 0 和 n-1 之间(包含 0 和 n-1)的下......
  • 动态dp & 矩阵加速递推
    广义矩阵乘法我们定义两个矩阵\(A,B\)在广义矩阵乘法下的乘积为\(C\),其中\[C=\begin{bmatrix}\max\limits_{i=1}\limits^{m}A_{1,i}+B_{i,1}&\max\limits_{i=1}\limits^{m}A_{1,i}+B_{i,2}&\dots&\max\limits_{i=1}\limits^{m}A_{1,i}+B_{i,k}\\\......
  • C/C++语言基础--指针三大专题详解2(指针与数组关系,动态内存分配,代码均可)
    本专栏目的更新C/C++的基础语法,包括C++的一些新特性前言指针是C/C++的灵魂,和内存地址相关联,运行的时候速度快,但是同时也有很多细节和规范要注意的,毕竟内存泄漏是很恐怖的指针打算分三篇文章进行讲解,本专题是二,介绍了指针和数组的关系、动态内存如何分配和释放等问题专题......
  • [oeasy]python0030_动态控制断点_breakpoints_debug_调试
     030_动态控制断点_breakpoints_debug_调试290播放·0赞同视频​设置断点_break_point_continue_运行到断点......
  • 动态表单后端设计
     动态表单通常用于收集各种不同类型的数据,这些数据可能随时间变化或根据用户的需求而变化。因此,数据库设计和接口设计需要足够灵活以适应不同的表单结构。以下是一些关于动态表单的数据库设计和接口设计的基本指导原则:数据库设计表单元数据表:form_id(表单ID)form_name(表......
  • 内存(动态开辟)———C语言
    内存管理: 1.C语言运行时的内存分配2.static关键字1.修饰变量局部变量:        <1>在编译的过程中,会在数据区为该变量开辟空间,如果代码中未对其进行初始化,则系统默认初始化为0。        <2>用static修饰的局部变量,会延长局部变量的生命周期#include<s......