Day42代码随想录动态规划part04:01背包问题的二维数组解法、01背包问题的一维数组解法、416. 分割等和子集

Day42 动态规划part03-01背包问题

01背包问题的二维数组解法

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

暴力解法:回溯法,枚举所有情况,每个物品是取与不取两个状态

二维数组方法

  • dp数组的含义:二维dp[i][j]数组:[0,i]之间的物品任取,放入容量为j的背包里
  • 递推公式:dp[i][j] 最后求的是两种情况的最大价值max
    • (1)不放物品i,最大价值是dp[i-1][j];
    • (2)放物品i, dp[i-1][j-weight[i]] + value[i];
  • 初始化:一定要和dp数组的定义吻合,否则到递推公式的时候就会越来越乱
    • dp[i][0]:首先从dp[i][j]的定义出发,如果背包容量j为0的话,即dp[i][0]=0,无论是选取哪些物品,背包价值总和一定为0。
    • dp[0][i]:根据状态转移方程 dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]); 可以看出i 是由 i-1 推导出来,那么i为0的时候就一定要初始化。dp[0][j],当j<weight[0]时为0,j >= weight[0]时,dp[0][j] 应该是value[0],因为背包容量放足够放编号0物品。
    • 其他下标: 从递推公式中看出,其他下标初始为什么数值都可以,因为都会被覆盖。
  • 遍历顺序:先遍历物品还是先遍历容量都可以
m,n = map(int, input().split())
weight = list(map(int, input().split()))
value = list(map(int, input().split()))
# print(m,n)
dp = [[0]*(n+1) for _ in range(m)]

# 初始化,dp[i][0]本身就都是0了,只需要初始dp[0][i]
for i in range(n+1):
    if i >= weight[0]:
        dp[0][i] = value[0]
# print(dp)

for i in range(1, m): #遍历物品
    for j in range(1, n+1): #遍历空间
        if j < weight[i]:
            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)
max_value = dp[m-1][n]
print(max_value)

01背包问题的一维数组解法

一维数组方法:核心想法,当前层i都是由上一层的i-1推导出来的,我们可以把上一层的拷贝到当前层进行计算,然后再用当前层的新计算值覆盖i+1层

  • dp数组含义:dp[j]容量为j的背包所能装的最大价值为dp[j]
  • 递归公式:dp[j]=max(dp[j], dp[j- weight[i]] + value[i]);dp[j]不放物品i,从上一层拷贝下来的
  • 初始化:dp[0]背包容量为0的最大价值为0,其余也都初始化成0(非负的最小值)是因为如果初始化成一个大的数求max时可能会有影响
  • 遍历顺序:先遍历物品,再遍历背包容量**(倒序),这是因为为了物品i只被放入1次**。因为二维dp数组不受上一层的影响,而1维是每次重复利用的。
    • 如果正序遍历:dp[1] = dp[1 - weight[0]] + value[0] = 15,dp[2] = dp[2 - weight[0]] + value[0] = 30,此时dp[2]就已经是30了,意味着物品0,被放入了两次,所以不能正序遍历。
    • 倒序就是先算dp[2]:dp[2] = dp[2 - weight[0]] + value[0] = 15 (dp数组已经都初始化为0),dp[1] = dp[1 - weight[0]] + value[0] = 15。所以从后往前循环,每次取得状态不会和之前取得状态重合,这样每种物品就只取一次了。
  • 对于一维dp只能先遍历物品,再遍历背包。背包容量一定是要倒序遍历(原因上面已经讲了),如果遍历背包容量放在上一层,那么每个dp[j]就只会放入一个物品,即:背包里只放入了一个物品。
for(int i = 0; i < weight.size(); i++) { // 遍历物品
    for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
        dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
    }
}
  • 推导:物品0重量1价值15,物品1重量3价值20,物品2重量4价值30

题目:卡码网46:46. 携带研究材料(第六期模拟笔试) (kamacoder.com)

m,n = map(int, input().split())
weight = list(map(int, input().split()))
value = list(map(int, input().split()))
# print(m,n)
dp = [0]*(n+1)

# 初始化,dp[i]本身就都是0了

for i in range(m): #遍历物品
    for j in range(n, weight[i]-1, -1): #遍历空间
	    #注意这里因为是倒叙,所以是从n开始!不是n+1
        # print(i,j, weight[i])
        dp[j] = max(dp[j], dp[j-weight[i]]+value[i])
            # pass
# print(dp)
max_value = dp[n]
print(max_value)

416. 分割等和子集

leetcode题目链接:416. 分割等和子集 - 力扣(LeetCode)

题意:给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

示例 1:

  • 输入: [1, 5, 11, 5]
  • 输出: true
  • 解释: 数组可以分割成 [1, 5, 5] 和 [11].

思路:只要找到集合里能够出现 sum / 2 的子集总和,就算是可以分割成两个相同元素和子集了。因为每个元素只能使用1次,所以是0-1背包问题

只有确定了如下四点,才能把01背包问题套到本题上来。

  • 背包的体积为sum / 2
  • 背包要放入的商品(集合里的元素)重量为 元素的数值,价值也为元素的数值;也就是之前的weight就是此时的value
  • 背包如果正好装满,说明找到了总和为 sum / 2 的子集。dp[sum/2] == sum/2
  • 背包中每一个元素是不可重复放入。
  1. 确定dp数组以及下标的含义:dp[j]表示 背包总容量(所能装的总重量)是j,放进物品后,背的最大重量为dp[j]。 当 dp[target] == target 的时候,背包就装满了。
  2. 确定递推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
  3. 初始化:本题题目中 只包含正整数的非空数组,所以非0下标的元素初始化为0就可以了。
  4. 遍历顺序:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历!
  5. 举例推导:
class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        n = len(nums)
        target = sum(nums)//2
        dp = [0]*(target+1)

        if sum(nums)%2 != 0:
            return False
        for i in range(n):
            # print(dp)
            for j in range(target, nums[i]-1, -1):
                dp[j] = max(dp[j], dp[j-nums[i]]+nums[i])
        # print(dp)
        if dp[target] == target:
            return True
        else:
            return False

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/585050.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于OpenCv的图像二值图和灰度直方图

⚠申明&#xff1a; 未经许可&#xff0c;禁止以任何形式转载&#xff0c;若要引用&#xff0c;请标注链接地址。 全文共计3077字&#xff0c;阅读大概需要3分钟 &#x1f308;更多学习内容&#xff0c; 欢迎&#x1f44f;关注&#x1f440;【文末】我的个人微信公众号&#xf…

Python新手入门基础英文笔记

1、字符串的操作 user&#xff1a;用户 name&#xff1a;名称/姓名 attibute&#xff1a;字段/属性 Value&#xff1a;值 2、重复/转换/替换/原始字符号 upper&#xff1a;上面 lower&#xff1a;下面 capitalize&#xff1a;用大写字母写或印刷 title&#xff1a;标题…

「笔试刷题」:求最小公倍数

一、题目 输入描述&#xff1a; 输入两个正整数A和B。 输出描述&#xff1a; 输出A和B的最小公倍数。 示例1 输入&#xff1a; 5 7 输出&#xff1a; 35 示例2 输入&#xff1a; 2 4输出&#xff1a; 4二、思路解析 这道题&#xff0c;也是模拟实现这一大类的一题…

探索的时光 (整数三分)

本题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 题目&#xff1a; 样例&#xff1a; 输入 5 3 2 1 2 3 输出 28 思路&#xff1a; 根据题意&#xff0c;已经给出了运算函数 当我们看到这些函数的时候&#xff0c;联想一下&#xff0c;它们的单调性&#xff0c;以…

Adobe PS 2023、Adobe Photoshop 2023下载教程、安装教程

Adobe Photoshop &#xff08;<-下载连接&#xff09;简介&#xff1a; Adobe Photoshop是一款广泛使用的图像处理软件&#xff0c;由Adobe公司开发。它提供了许多强大的工具和功能&#xff0c;可以用于图像编辑、合成、修饰、设计等各个领域。用户可以使用Photoshop来调整…

HotSpot VM概述

许多技术人员只把JVM当成黑盒&#xff0c;要想改善Java应用的性能和扩展性无疑是一项艰巨的任务。若要提高Java性能调优的能力&#xff0c;就必须对现代JVM有一定的认知。 HotSpot VM是JDK 1.3版本之后默认的虚拟机&#xff0c;目前是使用最广泛的Java虚拟机。本文主要介绍HotS…

行为型设计模式

一、责任链设计模式 &#xff08;一&#xff09;概念 使多个对象都有机会处理同一个请求&#xff0c;从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链&#xff0c;并沿着这条链传递该请求&#xff0c;直到有一个对象处理它为止。 &#xff08;二&#xf…

算法学习Day1——【数据结构】单调栈

1.什么是单调栈以及单调栈的作用 &#xff08;1&#xff09;定义 顾名思义&#xff0c;单调栈是一个有序的栈&#xff0c;可能从栈顶到栈底单调递增&#xff08;单调递增栈&#xff09;&#xff0c;也有可能从栈顶到栈底单调递减&#xff08;单调递减栈&#xff09;。 &…

芯启智行丨基于G32A1445的汽车音乐律动氛围灯解决方案

随着智能汽车技术的深度渗入&#xff0c;汽车照明作为汽车设计的重要组成部分&#xff0c;正在重塑驾驶员与汽车的互动方式&#xff0c;从简单的照明工具优化升级为承载更多丰富功能和不同应用场景的智能化安全装置。现代智能车型广泛配备了前照灯、车内环境氛围灯、尾灯等汽车…

栈和链表的区分

栈&#xff08;Stack&#xff09;&#xff1a; 栈是一种特殊的线性表&#xff0c;遵循“后进先出”&#xff08;Last In First Out, LIFO&#xff09;原则。栈通常用数组或链表来实现&#xff0c;但重点在于其操作的限制而非底层数据结构。无论使用顺序栈&#xff08;基于数组…

读懂一本书笔记

文章目录 引言 我是一个用读书改变自己生活的人01 会读书&#xff0c;更要会讲书复杂时代&#xff0c;阅读是大众反脆弱的武器你焦虑吗&#xff1f;如何从“单向度的人”变为“多向度的人”第一&#xff0c;读书是主动的学习方式第二&#xff0c;读书是有针对性的学习方式 讲书…

kettle下载安装

下载方式&#xff1a; 1.官网下载 kettle下载链接&#xff1a; 老网站下载链接&#xff1a;https://sourceforge.net/projects/pentaho/files/这个网站已经弃用了 新网站地址获取方法&#xff1a;老网站下载链接打开&#xff0c;可以看到一个pdf下载链接&#xff0c;下载pdf 打…

二维码门楼牌管理应用平台建设:共治力量信息管理的革新

文章目录 前言一、二维码门楼牌管理应用平台的建设背景二、共治力量信息管理的重要性三、二维码门楼牌管理应用平台在共治力量信息管理中的应用四、二维码门楼牌管理应用平台的优势与挑战五、结语 前言 随着信息技术的飞速发展&#xff0c;二维码门楼牌管理应用平台的建设已成…

Spark原理之Cache Table的工作原理及实现自动缓存重复表的思考

CACHE TABLE的能力 使用此语法&#xff0c;可以由用户自定义要缓存的结果集&#xff0c;实际上就是一个临时表&#xff0c;不过数据存储在Spark集群内部&#xff0c;由Application所分配的executors管理。 一旦定义了一个缓存表&#xff0c;就可以在SQL脚本中随处引用这个表名…

Android 11 裁剪系统显示区域(适配异形屏)

概述 在显示技术中&#xff0c;"OverScan"&#xff08;超扫描&#xff09;是一种调整显示图像边界的技术。通常情况下&#xff0c;OverScan 会在显示屏的边缘周围裁剪一小部分图像。这种裁剪是为了确保显示内容在屏幕上的完整可见性&#xff0c;尤其是在老式电视或投…

【Qt】QtCreator忽然变得很卡

1. 问题 Qt Creator忽然变得很卡。电脑里两个版本的Qt Creator&#xff0c;老版本的开启就卡死&#xff0c;新版本好一点&#xff0c;但是相比于之前也非常卡&#xff0c;最明显的是在 ctrl鼠标滚轮 放大缩小的时候&#xff0c;要卡好几秒才反应。 2. 解决方案 2.1 方法1 关…

XL520无线接收芯片,2.2ms超低启动时间,-110dBm高接收灵敏度

XL520接收芯片采用SOP8封装&#xff0c;适用于300MHz- 440MHz频率范围&#xff0c;正常工作电压范围2.0~5.5V&#xff0c;工作电流在3.0~3.2mA之间。它具有快速的启动时间&#xff08;2.2ms&#xff09;和高达-110dBm的接收灵敏度&#xff0c;非常适合对低功耗要求严格的设备。…

测试工程师——招聘分析

测试工程师 随着互联网行业的高速发展,快速高质量的产品版本迭代成为企业始终立于不败之地的迫切需求,而在短期迭代的快节奏中,传统测试工作面对更大压力,无法持续提供高效率高质量的人力支撑,所以越来越多的企业需要技术更为全面的测试开发工程师。测试开发 本质上属于测…

Web安全的最后一道防线:细谈Gobuster的目录/文件/Vhost/DNS子域名暴力破解艺术

一、前言 Gobuster是一款用go语言编写的对于网站目录/文件、DNS子域、虚拟主机vhost进行暴力穷举的开源工具&#xff0c;常用于安全领域&#xff0c;其常用的暴力破解模式到目前为止&#xff08;3.6版本&#xff09;有如下几种&#xff1a; 模式含义dir最经典的文件路径/目录破…

深入Rust标准库:必备的Rust语言高级指南

&#x1f482; 个人网站:【 摸鱼游戏】【神级代码资源网站】【工具大全】&#x1f91f; 一站式轻松构建小程序、Web网站、移动应用&#xff1a;&#x1f449;注册地址&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交…