算法记录 | Day42 动态规划

news2024/11/19 1:48:59

416.分割等和子集1

01 背包

0-1 背包问题

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

img

**0-1 背包问题的特点:**每种物品有且仅有 1 件,可以选择不放入背包,也可以选择放入背包。

01背包问题 二维

使用二维数组

思路 :

  1. 确定dp数组(dp table)以及下标的含义:dp[i] [j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少**。

    动态规划-背包问题1

  2. 确定递推公式: dp[i] [j] = max(dp[i - 1] [j], dp[i - 1] [j - weight[i]] + value[i]);

    • 不放东西 :由dp[i - 1] [j]推出,即背包容量为j,里面不放物品i的最大价值,此时dp[i] [j]就是dp[i - 1] [j](其实就是当物品i的重量大于背包j的重量时,物品i无法放进背包中,所以被背包内的价值依然和前面相同。)
    • 放东西 :由dp[i - 1] [j - weight[i]]推出,dp[i - 1] [j - weight[i]] 为背包容量为j - weight[i]的时候不放物品i的最大价值,那么dp[i - 1] [j - weight[i]] + value[i] 物品i的价值),就是背包放物品i得到的最大价值
  3. dp数组如何初始化:

    • 首先从dp[i][j]的定义出发,如果背包容量j为0的话,即dp[i][0],无论是选取哪些物品,背包价值总和一定为0。如图:

    动态规划-背包问题2

    • 其他情况。

    状态转移方程 dp[i] [j] = max(dp[i - 1] [j], dp[i - 1] [j - weight[i]] + value[i]); 可以看出i 是由 i-1 推导出来,那么i为0的时候就一定要初始化。

    dp[0] [j],即:i为0,存放编号0的物品的时候,各个容量的背包所能存放的最大价值。

    那么很明显当 j < weight[0]的时候,dp[0] [j] 应该是 0,因为背包容量比编号0的物品重量还小。

    当j >= weight[0]时,dp[0] [j] 应该是value[0],因为背包容量放足够放编号0物品。

    动态规划-背包问题7

  4. 确定遍历顺序:先遍历 物品还是先遍历背包重量呢?其实都可以!! 但是先遍历物品更好理解

  5. 举例推导dp数组

bai

先遍历物品

def test_2_wei_bag_problem1(bag_size, weight, value) -> int:
	rows, cols = len(weight), bag_size + 1
	dp = [[0 for _ in range(cols)] for _ in range(rows)]

	# 初始化dp数组.
	for i in range(rows):
		dp[i][0] = 0
	first_item_weight, first_item_value = weight[0], value[0]
	for j in range(1, cols):
		if first_item_weight <= j:
			dp[0][j] = first_item_value

	# 更新dp数组: 先遍历物品, 再遍历背包.
	for i in range(1, len(weight)):
		cur_weight, cur_val = weight[i], value[i]
		for j in range(1, cols):
			if cur_weight > j: # 说明背包装不下当前物品.
				dp[i][j] = dp[i - 1][j] # 所以不装当前物品.
			else:
				# 定义dp数组: dp[i][j] 前i个物品里,放进容量为j的背包,价值总和最大是多少。
				dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - cur_weight]+ cur_val)

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

01.背包问题知识(一) | 算法通关手册 (itcharge.cn)

1.定义状态 dp[i] [w]表示为:前 i 件物品放入一个最多能装重量为 w 的背包中,可以获得的最大价值。

2.状态dp[i] [w] 是一个二维数组,其中第一维代表**「当前正在考虑的物品」**,第二维表示「当前背包的载重上限」,二维数组值表示「可以获得的最大价值」。

3.状态方程:dp[i] [w] = max(dp[i - 1] [j], dp[i - 1] [w - weight[i-1]] + value[i-1])

4.初始化:

  • 如果背包载重上限为 0,则无论选取什么物品,可以获得的最大价值一定是 0,即 ,dp[i] [0] =0,0≤i≤size。
  • 无论背包载重上限是多少,前 0 件物品所能获得的最大价值一定为 0,即 ,dp[0] [w] = 0,0≤w≤W。
class Solution:
    # 思路 1:动态规划 + 二维基本思路
    def zeroOnePackMethod1(self, weight: [int], value: [int], W: int):
        size = len(weight)
        dp = [[0 for _ in range(W + 1)] for _ in range(size + 1)]
        
        # 枚举前 i 种物品
        for i in range(1, size + 1):
            # 枚举背包装载重量
            for w in range(W + 1):
                # 第 i - 1 件物品装不下
                if w < weight[i - 1]:
                    # dp[i][w] 取「前 i - 1 件物品装入载重为 w 的背包中的最大价值」
                    dp[i][w] = dp[i - 1][w]
                else:
                    # dp[i][w] 取「前 i - 1 件物品装入载重为 w 的背包中的最大价值」与「前 i - 1 件物品装入载重为 w - weight[i - 1] 的背包中,再装入第 i - 1 物品所得的最大价值」两者中的最大值
                    dp[i][w] = max(dp[i - 1][w], dp[i - 1][w - weight[i - 1]] + value[i - 1])
                    
        return dp[size][W]

物品下标从1开始,范围变更为1,size+1

01背包问题 一维

动规五部曲分析如下:

1.确定dp数组的定义:在一维dp数组中,dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j]。

2.一维dp数组的递推公式:dp[j] = max(dp[j], dp[j - weight[i]] + value[i])

3.初始化:无论背包载重上限为多少,只要不选择物品,可以获得的最大价值一定是 0,dp[0]就应该是0

4.一维dp数组遍历顺序:先遍历物品再遍历背包(背包倒序遍历)倒序遍历是为了保证物品i只被放入一次

物品0的重量weight[0] = 1,价值value[0] = 15

如果正序遍历

dp[1] = dp[1 - weight[0]] + value[0] = 15

dp[2] = dp[2 - weight[0]] + value[0] = 30 (dp[1]更新)

倒序就是先算dp[2]

dp[2] = dp[2 - weight[0]] + value[0] = 15 (dp数组已经都初始化为0,即dp[1]=0)

dp[1] = dp[1 - weight[0]] + value[0] = 15

5.举例推导dp数组

动态规划-背包问题9

def test_1_wei_bag_problem():
    weight = [1, 3, 4]
    value = [15, 20, 30]
    bag_weight = 4
    # 初始化: 全为0
    dp = [0] * (bag_weight + 1)

    # 先遍历物品, 再遍历背包容量
    for i in range(len(weight)):
        for j in range(bag_weight, weight[i] - 1, -1):
            # 递归公式
            dp[j] = max(dp[j], dp[j - weight[i]] + value[i])

    print(dp)

test_1_wei_bag_problem()

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

01.背包问题知识(一) | 算法通关手册 (itcharge.cn)

1.定义状态 dp[w]表示为:将物品放入一个最多能装重量为 w 的背包中,可以获得的最大价值。

2.dp[w] = max(dp[w], dp[w - weight[i-1]] + value[i-1])

3.初始化:无论背包载重上限为多少,只要不选择物品,可以获得的最大价值一定是 0,即 dp[w] = 0, 0<=w<=W

class Solution:
    # 思路 2:动态规划 + 滚动数组优化
    def zeroOnePackMethod2(self, weight: [int], value: [int], W: int):
        size = len(weight)
        dp = [0 for _ in range(W + 1)]
        
        # 枚举前 i 种物品
        for i in range(1, size + 1):
            # 逆序枚举背包装载重量(避免状态值错误)
            for w in range(W, weight[i - 1] - 1, -1):
                # dp[w] 取「前 i - 1 件物品装入载重为 w 的背包中的最大价值」与「前 i - 1 件物品装入载重为 w - weight[i - 1] 的背包中,再装入第 i - 1 物品所得的最大价值」两者中的最大值
                dp[w] = max(dp[w], dp[w - weight[i - 1]] + value[i - 1])
                
        return dp[W]

物品下标从1开始,范围变更为1,size+1

416.分割等和子集

思路:

转换为 01背包

  • 背包的体积为sum / 2
  • 背包要放入的商品(集合里的元素)重量为 元素的数值,价值也为元素的数值
  • 背包如果正好装满,说明找到了总和为 sum / 2 的子集。
  • 背包中每一个元素是不可重复放入。

动规五部曲

1.确定dp数组以及下标的含义:如果背包容量为target, dp[target]就是装满 背包之后的重量,所以 当 dp[target] == target 的时候,背包就装满了

2.确定递推公式

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

相当于背包里放入数值,那么物品i的重量是nums[i],其价值也是nums[i]

所以递推公式:

dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);

3.dp数组如何初始化:01背包,一维dp初始化,dp[0] =0

4.确定遍历顺序:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历

5.举例推导dp数组:

dp[j]的数值一定是小于等于j的。

如果dp[j] == j 说明,集合中的子集总和正好可以凑成总和j,理解这一点很重要。

416.分割等和子集2

一维数组

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

二维数组

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        target = sum(nums)
        if target % 2 == 1: return False
        target //= 2
        dp =[[0 for _ in range(target+1)] for _ in range(len(nums))]

        for i in range(len(nums)):
            dp[i][0]= 0

        for j in range(target+1):
            if nums[0] <=j:
                dp[0][j] = nums[0]

        # 先遍历物品再遍历背包
        for i in range(len(nums)):
            cur_weight = nums[i]
            cur_value = nums[i]
            for j in range(target+1):
                if cur_weight > j:
                    dp[i][j] = dp[i-1][j]
                else:
                    dp[i][j]  = max(dp[i-1][j],dp[i-1][j-cur_weight]+cur_value)
        return target == dp[-1][target]
class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        target = sum(nums)
        if target % 2 == 1: return False
        target //= 2
        dp =[[0 for _ in range(target+1)] for _ in range(len(nums)+1)]

        # 先遍历物品再遍历背包
        for i in range(1,len(nums)+1):
            for j in range(target+1):
                if  j < nums[i-1] :
                    dp[i][j] = dp[i-1][j]
                else:
                    dp[i][j]  = max(dp[i-1][j],dp[i-1][j-nums[i-1]]+nums[i-1])
        return target == dp[-1][target]

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

28. Python logging日志模块下(适合小白)

28. Python logging日志模块下&#xff08;适合小白&#xff09; 文章目录 28. Python logging日志模块下&#xff08;适合小白&#xff09;1. %占位符格式化语法知识回顾2. basicConfig函数的参数3. format参数&#xff1a;设置输出的格式3.1 添加%(asctime)s字段输出日志发生…

电子商务网站上的API攻击如何泄漏PII

本稳重点分享&#xff1a; 以影子 API为目标的 API 攻击 电子商务网站上的 API 攻击如何泄漏 PII 对 API 运行时安全性重要性的看法 API 渗透测试指南 以影子 API为目标的 API 攻击 首先是DarkReading最近的一个研究的报告&#xff0c;该报告显示&#xff0c;大约50亿&am…

20+ Prompt工具网站汇总;我用AI工具开了一家「无人公司」;如何10分钟上线一个AI导航网站;第一部AIGC中英双语图文辞典 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 『MidJourney Prompt工具网站』加速生成与优化&#xff0c;持续更新中 ShowMeAI知识星球 | 资源标签&#xff1a;找工具 这是一个总结…

【unity专题篇】——GUI(IMGUI)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

tcp,udp一些列问题

&#xff08;tcp,udp基本介绍&#xff0c;三握四挥等&#xff09;七层模型主要知识点等 OSI七层模型其功能简介 分层机制体现了分治的思想&#xff0c;每一层为上一层提供保障屏蔽异构。 物理层&#xff1a;规定了一系列的物理、电气、接口标准&#xff0c;传输的是比特流&…

DAY05_面向对象基础

面向对象并不是一个技术&#xff0c;而是一种指导思想。 为什么要用面向对象编程&#xff1f; 因为生活中&#xff0c;我们解决问题时&#xff0c;就是采用这种指导思想去解决的。所以&#xff0c;我们写程序去解决问题时&#xff0c;如果也能采用这种指导思想就会使得程序变…

LVS+keepalived 群集

Keepalived及其工作原理 Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案&#xff0c;可以解决静态路由出现的单点故障问题 在一个LVS服务集群中通常有主服务器&#xff08;MASTER&#xff09;和备份服务器&#xff08;BACKUP&#xff09;两种角色的服务器&#xff…

链接伪类选择器(上)

知识点&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta http-equiv"X-UA-Compatible" content"IEedge"> <meta name"viewport" c…

java方法的重载

java中有很多方法是可以通过重载的方式实现的&#xff0c;这是 Java语言的一大特色&#xff0c;但是同时也为开发人员带来了一些麻烦&#xff0c;不知道怎么去调用这些方法&#xff0c;而且还容易出现一种情况就是&#xff1a;明明已经调用过了一个方法&#xff0c;但为什么又要…

Ansys Zemax | 如何模拟双折射偏振器件

这篇文章介绍了什么是双折射现象、如何在OpticStudio中模拟双折射 (birefringence)、如何模拟双晶体的双折射偏振器以及如何计算偏振器的消光比。&#xff08;联系我们获取文章附件&#xff09; 什么是双折射现象 一般的光学材料都是均匀的各向同性的&#xff0c;也就是说无论光…

等级保护、风险评估和安全测评分别是什么?

2022-06-17 15:17 迈入“等保2.0时代”以后&#xff0c;我国对于等级保护的要求更为严格和具体。等级保护、风险评估和安全测评这三个词&#xff0c;也因此总是出现在人们的视野之中&#xff0c;还总是被混淆。那这三者究竟分别是什么呢&#xff1f;如何区分它们&#xff1f;它…

如何以产品经理思维打造一所高品质学校?

学校的建设与管理真不是一件容易事。2023年03月17日&#xff0c;山东菏泽市曹县一家长投诉某中学课业繁重&#xff0c;孩子经常写作业到半夜&#xff1b;2023年4月4日&#xff0c;张先生在华龙网重庆网络问政平台投诉万州区某中学伙食差&#xff0c;指出“发灰的洋葱&#xff0…

本地运行 minigpt-4

1.环境部署 参考官方自带的README.MD&#xff0c;如果不想看官方的&#xff0c;也可参考MiniGPT-4&#xff5c;开源免费可本地进行图像对话交互的国产高级大语言增强视觉语言理解模型安装部署教程 - openAI 当然&#xff0c;所有的都要按照作者说明来&#xff0c;特别是版本号…

练好基本功,优秀工程师成长第一步

计算机基础作用 举例1&#xff1a;若是我们要开发大规模应用系统&#xff0c;如电商服务系统&#xff0c;要考虑很多 1. 这个服务应用要用什么语言来编写&#xff1f; 2. 是采用单体进程&#xff0c;还是用多个进程来协同工作&#xff1f; 3. 如何管理长期使用的内存空间&a…

( 栈和队列) 155. 最小栈 ——【Leetcode每日一题】

❓155. 最小栈 难度&#xff1a;中等 设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。void push(int val) 将元素val推入堆栈。void pop() 删除堆栈顶部的元素。…

WiFi电子标签简介

WiFi电子标签系统概述&#xff1a; WIFI电子办公标牌系统是一种先进的无线自动更新系统&#xff0c;取代了传统的纸质标牌/桌牌需要人工更换的方式。WIFI ESL系统只需要一个电子办公标志设备&#xff0c;让它在办公或会议空间工作&#xff0c;快速改变人员或会议信息。这是一种…

Docker -compose 安装使用

命令 总结 yum install docker-compose-plugin docker compose version docker compose up docker compose up -d相关的配置。 创建docker-conpose 目录&#xff0c;并创建docker-compose.yml文件 version: 3 services: mysql: image: mysql restart: always co…

【基础算法】二叉树相关题目

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招算法的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于代码随想录进行的&#xff0c;每个算法代码参考leetcode高赞回答和…

[ICLR 2023] Token Merging: Your ViT But Faster

Contents IntroductionToken MergingExperimentsImage ExperimentsDesign choicesModel SweepComparison to Other WorksVisualizations Video ExperimentsAudio Experiments References Introduction 作者提出了一种 token 合并方法 Token Merging (ToMe)&#xff0c;能够在不…

【Tasking_IDE】-1-如何让目录下的C文件不参与编译

案例背景&#xff1a; 当您在使用Tasking TriCore Eclipse IDE集成开发环境编译时&#xff0c;是不是有时遇到这样一个问题&#xff1a;导入了一个算法/驱动文件夹&#xff0c;但文件夹里面不是所有的C文件都要参与编译&#xff0c;于是您可能想到把这些“不参与编译的文件”删…