代码随想录训练营Day31:动态规划3:0-1背包

1.0-1背包基础

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

1.1动态规划五部曲

  1. 确定dp数组以及下标的含义:dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。在后续的程序中都是默认背包的容量为i,物品的类别为j,保证统一。

2.确定递推公式

  • 不放物品i:由dp[i - 1][j]推出,即背包容量为j,里面不放物品i的最大价值,此时dp[i][j]就是dp[i - 1][j]。(其实就是当物品i的重量大于背包j的重量时,物品i无法放进背包中,所以背包内的价值依然和前面相同。)
  • 放物品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得到的最大价值

所以递归公式: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

3.初始化:需要根据具体的进行具体的初始化

4.那么问题来了,先遍历 物品还是先遍历背包重量呢?

其实都可以!! 但是先遍历物品更好理解。对于先遍历物品再遍历容量,简称为组合问题:这种情况下的遍历物品的顺序是一个固定的。

// weight数组的大小 就是物品个数
for(int i = 1; i < weight.size(); i++) { // 遍历物品
    for(int j = 0; j <= bagweight; j++) { // 遍历背包容量
        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]);

    }
}

先遍历背包,再遍历物品,也是可以的!(注意我这里使用的二维dp数组)。这种可以称之为排列问题可能会出现相同的结果但是不同的排列方式

例如这样:

// weight数组的大小 就是物品个数
for(int j = 0; j <= bagweight; j++) { // 遍历背包容量
    for(int i = 1; i < weight.size(); i++) { // 遍历物品
        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]);
    }
}

5.举例:跳过,直接看下面的代码

2.416分割等和子集

第一种方法:动态规划的方法

理论分析:首先要分割成等和的子集,要满足的第一个条件就是其累加和能被2整除。

动态规划五部曲

1.dp[j]表示 背包总容量(所能装的总重量)是j,放进物品后,背的最大重量为dp[j]

2.递推公式:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);//分为填不添加这个数情况下的最大累加和。二维状态下是:dp[i][j] = max(dp[i-1][j], dp[i-1][j - weight[i]] + value[i]):i表示物品j表示容量

3.初始化:首先初始化的长度为target+1,因为我们只需要找到一个容量为sum一半的能够全部装满就代表还存在另外一部分。

4.确定遍历顺序:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历!因为这样可以避免重复存放。可以看到上面的二维的递推公式,首先遍历的是物品,其次遍历的是容量,如果内部的容量是正序,那么会出现一个物品被多次使用。比如有1 2;2 3(重量 价值)的物品,这样的情况,正序遍历出现的结果就是dp数组为[2,4]而不是[2,3]的情况了。

class Solution {
public:
    //动态规划的方法
    bool canPartition(vector<int>& nums) {
        int sum = 0;
        int n = nums.size();
        for(int i = 0;i<n;i++){
            sum += nums[i];
        }
        if(sum%2 ==1)return false;
        int target = sum/2;
        vector<int> dp(1+target,0);//生成一个dp数组
        for(int i = 0;i<n;i++){
            for(int j = target;j>=nums[i];j--){
                dp[j] = max(dp[j],dp[j-nums[i]]+nums[i]);//分加不加的情况下的最大值
            }
        }
        if(dp[target] == target)return true;
        return false;

    }
};

3.最后一块石头的重量

首先就是分析题意:我该如何让最后的石头的重量最小呢?就是通过将其分成两部分,两部分的差值越小那么对应的最后能够得到的重量也就越小。那么将其化成一个背包问题就是在求容量为target下能够存放的最大的重量为多少即0-1背包问题。

动态规划五部曲

1.dp[j]:容量为j时候的最大价值(重量)。

2.递推公式:dp[j] = max(dp[j],dp[j-stones[i]]+stones[i]);//在这个里面重量和价值都是用stones[i]来表示的,所以得到上述的公式,具体可以参考前面这一题的思路。

3.初始化:首先来说的话我们要用sum来确定总重量,然后确定dp数组的空间,应该生成的vector<int> dp(1+sum/2,0)的,但是按照题目给定了最多只有3000个,所以可以直接创建一个大的空间(1500>sum/2)。

4.循环的遍历方向:参照前面的分割等和子集。如果是一维的需要怎样的操作。

注意事项:最后返回的是 return sum - 2*dp[target];因为此时分成的两部分的重量分别为sum -dp[target]和dp[target],且必定是target>=dp[target]所以最后返回的是两者的差值即可。

class Solution {
public:
    //dp数组,求得是能够背得的最大的重量,使用这种方法,巧妙的将碰撞的减法问题给反向思考为一个加法问题,最后相减来确定最小的重量
    int lastStoneWeightII(vector<int>& stones) {
        vector<int> dp(1501,0);
        int sum = accumulate(stones.begin(),stones.end(),0);//求累加和
        int target = sum/2;
        for(int i = 0; i<stones.size();i++){
            for(int j = target;j>=stones[i];j--){
                dp[j] = max(dp[j],dp[j-stones[i]]+stones[i]);
            }
        }
        return sum - 2*dp[target];
    }
};

4.494目标和

结题思路看下面的注释部分。

动态规划五部曲:

1.dp[j]:代表容量为j的最大价值(和)的组合数。

2.递推公式:dp[j] += dp[j-nums[i]];组合类问题就是对应的多个的累加和。

3.初始化:在这个地方初始化需要初始化的长度是dp(avg+1);而不需要sum+1,因为left = avg;

4.遍历顺序:对于组合问题:应该先遍历背包再遍历容器。再就是遍历方向的问题:里面那个是从大往小的进行遍历,同前面一样是为了避免重复的情况。参考分割等和子集问题。

class Solution {
public:
    //在这个里面,left代表的是正数的部分,right代表的是负数的部分
    //left + right = sum(定值)
    //left - right = target(定值)
    //left = (sum + target)/2;//所以此时两者的累加和一定能被2整除才行。
    //还需要考虑的就是sum>=abs(target)不然无法保证能够完成累加到指定的为止
    //所以此时dp[i]表示的就是累加和为i的个数
    //dp[j] += dp[j - nums[i]];//每一个nums[i]都对应的一个dp[j - nums[i]]种方法可以累加到这里
    int findTargetSumWays(vector<int>& nums, int target) {
        int n = nums.size();
        
        int sum = accumulate(nums.begin(),nums.end(),0);//求和,后面那个应该是初始化的赋值
        if(abs(target)>sum)return 0;
        if((target+sum)%2==1) return 0;
        int avg = (target+sum)/2;
        vector<int> dp(avg+1);
        dp[0] = 1;
        for(int i = 0;i<nums.size();i++){
            for(int j = avg;j>= nums[i];j--){
                dp[j] += dp[j-nums[i]];
            }
        }
        return dp[avg];
    }
};

5.474一和零

1.dp[i][j]:i表示0的个数,j表示1的个数。dp[i][j]表示当前容量下的最大的个数。

2.递推公式: dp[i][j] = max(dp[i][j],dp[i-zeros][j-ones]+1);//其中dp[i-zeros][j-ones]表示的是dp[j-weight[i]]的意思,1:表示value[i].

3.初始化:默认开始的时候都是0。

4.遍历顺序:反序遍历保证不重复。

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        vector<vector<int>> dp(m+1,vector<int>(n+1,0));//生成一个dp数组,用于确定有i个1,j个0
        for(auto str:strs){
            int zeros = 0;
            int ones = 0;
            for(auto st:str){
                if(st == '0'){
                    zeros++;
                }else{
                    ones++;
                }
            }
            for(int i = m;i >=zeros;i--){
                for(int j = n;j>=ones;j--){
                    dp[i][j] = max(dp[i][j],dp[i-zeros][j-ones]+1);
                }
            }
        }
        return dp[m][n];
    }
};

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

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

相关文章

sql操作、发送http请求和邮件发送 全栈开发之路——后端篇(2)

全栈开发一条龙——前端篇 第一篇&#xff1a;框架确定、ide设置与项目创建 第二篇&#xff1a;介绍项目文件意义、组件结构与导入以及setup的引入。 第三篇&#xff1a;setup语法&#xff0c;设置响应式数据。 第四篇&#xff1a;数据绑定、计算属性和watch监视 第五篇 : 组件…

RK3566(泰山派):3.1寸屏幕D310T9362V1SPEC触摸驱动(竖屏)

RK3566&#xff08;泰山派&#xff09;&#xff1a;3.1寸屏幕D310T9362V1SPEC触摸驱动&#xff08;竖屏&#xff09; 文章目录 RK3566&#xff08;泰山派&#xff09;&#xff1a;3.1寸屏幕D310T9362V1SPEC触摸驱动&#xff08;竖屏&#xff09;电路配置i2c1设备树创建驱动编写…

什么是50etf期权?期权的三级交易权限是什么?

今天期权懂带你了解什么是50etf期权&#xff1f;期权的三级交易权限是什么&#xff1f;期权三级交易权限&#xff0c;作为股票期权交易中的最高级别权限&#xff0c;赋予了投资者更广泛、更灵活的交易选择和策略。 什么是50etf期权&#xff1f; ETF期权是指在支付一定额度的权…

如何让机器理解人类语言?Embedding技术详解

如何让机器理解人类语言&#xff1f;Embedding技术详解 文章目录 如何让机器理解人类语言&#xff1f;Embedding技术详解介绍什么是词嵌入&#xff1f;什么是句子嵌入&#xff1f;句子嵌入模型实现句子嵌入的方法值得尝试的句子嵌入模型 句子嵌入库实践Step 1Step 2Step 3 Doc2…

SwiftUI中三大渐变色的介绍

在SwiftUI中&#xff0c;渐变色是一种常用的视觉效果&#xff0c;用于创建平滑过渡的颜色变化。通过使用渐变色&#xff0c;我们可以实现丰富多彩的界面设计&#xff0c;增强用户体验。 1. 渐变色的种类和用途 种类&#xff1a; 线性渐变&#xff08;Linear Gradient&#x…

oracle多条重复数据,取最新的

1、原理讲解-可直接看2 筛选出最新的 SELECT * FROM ( SELECT t.*, ROW_NUMBER() OVER (PARTITION BY LOCALAUTHID ORDER BY LASTUPDATETIME DESC) AS rn FROM USER_LOCALAUTH_STATE t ) t WHERE t.rn 1; 解释&#xff1a; 这个序号是基于[LOCALAUTHID]字段进行分…

计算机vcruntime140.dll找不到如何修复,分享5种靠谱的修复教程

当您在运行某个应用程序或游戏时遇到提示“找不到vcruntime140.dll”&#xff0c;这通常意味着系统中缺少了Visual C Redistributable for Visual Studio 2015或更高版本的一个重要组件。这个错误通常发生在运行某些程序时&#xff0c;系统无法找到所需的动态链接库文件。小编将…

ASP.NET医药进销存系统

摘 要 目前&#xff0c;大中型城市的多数药品店已经实现了商品管理、客户管理、销售管理及销售管理等的信息化和网络化&#xff0c;提高了管理效率。但是&#xff0c;在大多数小药品店&#xff0c;药品店管理仍然以传统人工管理为主&#xff0c;特别是在药品的采购、销售、库…

电商核心技术揭秘56:客户关系管理与忠诚度提升

相关系列文章 电商技术揭秘相关系列文章合集&#xff08;1&#xff09; 电商技术揭秘相关系列文章合集&#xff08;2&#xff09; 电商技术揭秘相关系列文章合集&#xff08;3&#xff09; 文章目录 引言客户关系管理&#xff08;CRM&#xff09;的重要性提升顾客体验数据驱…

Springboot打包jar如何后台启动和查看日志?

如何后台启动Spring Boot的fat jar 使用nohup命令启动&#xff1a; 在Linux或Unix系统中&#xff0c;你可以使用nohup命令来启动jar包&#xff0c;以确保即使你关闭了终端或断开了SSH连接&#xff0c;程序仍然可以在后台运行。命令格式如下&#xff1a;nohup java -jar yourapp…

PCie协议之-TLP Header详解(一)

✨前言&#xff1a; 在PCIe通信过程中&#xff0c;事务层数据包&#xff08;Transaction Layer Packets&#xff0c;简称TLP&#xff09;扮演着非常重要的角色。TLP用于在设备之间传递数据和控制信息&#xff0c;它们是PCIe的基本信息传输单元。 TLP可分为几个部分&#xff0c…

硬盘格式化后能恢复数据吗?这个恢复方法电脑小白也能用!

硬盘格式化后能恢复数据吗&#xff1f;对于这个问题需要先了解清楚硬盘格式化和数据恢复的原理了。 目前我们所说的硬盘格式化通常都是指“快速格式化”&#xff0c;一般来说当我们在清理磁盘空间或者新建磁盘分区时会使用到这个功能&#xff0c;最终的结果就是清除掉磁盘上的…

“打工搬砖记”中吃什么的轮盘功能实现(二)

文章目录 打工搬砖记转盘主要的逻辑实现转盘的素材小结 打工搬砖记 先来一个吃什么轮盘的预览图&#xff0c;这轮盘文案加字呈圆形铺出来&#xff0c;开始后旋转到指定的选项处停下来。 已上线小程序“打工人搬砖记”&#xff0c;可以扫码进行预览观看。 转盘主要的逻辑实现…

【Unity Shader入门精要 第7章】基础纹理补充内容:MipMap原理

1.纹理采样 我们对纹理采样进行显示的过程&#xff0c;可以理解为将屏幕上的一个像素&#xff08;下文用像素表示&#xff09;映射到纹理上的一个像素&#xff08;下文用纹素表示&#xff09;&#xff0c;然后用纹理上的这个像素的颜色进行显示。 理想情况下&#xff0c;屏幕…

AcqKnowledge 5.0使用方法

Biopac 数据导入 matlab 处理方法 第一步&#xff1a;在 AcqKnowledge 软件中&#xff0c;将数据通道的 mark 信息导入到 Graph&#xff0c;并将数据存储为 acq3 的格式 第二步&#xff1a;MATLAB中读取acq3文件脚本 clc clear %%%所有被试这一层路径 pathsub fullfile(file…

【JavaEE】HTTP 协议

文章目录 一、HTTP 协议1、HTTP 是什么2、理解 "应用层协议"3、理解 HTTP 协议的工作过程4、HTTP 协议格式5、HTTP 请求 (Request)5.1 认识 URL 6、 二、HTTPS1、HTTPS是什么2、"加密" 是什么3、HTTPS 的工作过程3.1 对称加密3.2 非对称加密3.3 证书3.4 完…

iOS——消息传递和消息转发

消息传递&#xff08;Message Passing&#xff09;&#xff1a; 在 iOS 中&#xff0c;消息传递机制是基于 Objective-C 语言的动态性质的一种编程方式。这种机制主要涉及到两个概念&#xff1a;发送者&#xff08;即消息的发送对象&#xff09;和接收者&#xff08;即消息的接…

RS422一主多从MAX3490

RS422一主多从MAX3490 最近项目用到了RS422一主多从&#xff0c;一个主机4个从机。芯片用的MAX3490&#xff0c;几经折腾&#xff0c;最终只能从一拖4改为一拖2。 主机发送端&#xff0c;从机4个接收端都是正常的&#xff0c;没有问题。波形非常完美&#xff0c;没有太大变形 …

matlab使用2-基础绘图

matlab使用2-基础绘图 文章目录 matlab使用2-基础绘图1. 二维平面绘图2. 三维立体绘图3. 图形窗口的分割 1. 二维平面绘图 % 创建一些二维数据 x 0:0.01:10; % x轴的数据点&#xff0c;从0到10&#xff0c;间隔为0.01 y sin(x); % y轴的数据点&#xff0c;是x的正弦…

版本控制:软件开发的基石(一文读懂版本控制)

未经允许&#xff0c;禁止转载&#xff01; 在现代软件开发中&#xff0c;版本控制是不可或缺的工具。它帮助开发者跟踪和管理代码的变化&#xff0c;协作完成项目&#xff0c;并确保代码的完整性和安全性。本文将基于Git官网的视频“什么是版本控制”来深入探讨版本控制的基本…