当前位置: 首页 > article >正文

代码随想录-训练营-day30

今天我们要进入动态规划的背包问题,背包问题也是一类经典问题了。总的来说可以分为:

今天让我们先来复习0-1背包的题目,这也是所有背包问题的基础。所谓的0-1背包问题一般来说就是给一个背包带有最大容量,然后给一个物体对应的需要的容量和价格的表格,且每个物体只能取一次,问我们怎么得到最大价值。

我们依然使用动态规划的既定套路来做:

第一步,确定我们的dp数组的含义,首先明确的是:我们需要一个二维的dp数组,因为我们需要同时表示背包的容量和物体,也就是dp[i][j]表示的是容量为j的背包中遍历到下标为i的物体时的最大价值。

第二步,递推公式,我们可以设想一下dp[i][j]可以怎么由之前的值得到,对于容量为j的背包来说,物体i有两种情况:放或者不放,不放的话就是dp[i-1][j],放的话就是dp[i-1][j-weights[i]]+values[i](要放下标为i的物体需要在背包中预留出他的容量),所以递推公式就是:

dp[i][j]=max(dp[i-1][j],dp[i-1][j-weights[i]]+values[i])

第三步,初始化,我们要如何初始化我们的dp数组呢?显然dp[0][0]=0(容量为0),事实上,所有容量为0的背包的初始值都应该是0,也就是dp[i][0]=0;那么反过来的dp[0][j]呢?这个就要看我们下标为0的物品重量与我们的j的关系了,如果大于j显然也是0,如果小于j的话那就可以是values[0]。那么dp[0][j]应该就是从j=weights[0]开始,遍历到最后。

最后的初始化结果如下:

遍历顺序的话,也很有讲究,我们是该先遍历物品呢,还是该先遍历背包呢?

答案其实是,对于0-1背包来说,都可以。

我们拿一个图来说明:

由我们的递推公式已知,我们的dp[i][j]的更新都是依靠左上角的值来更新的,那么我们先遍历背包再遍历物品就是先横向再纵向,反之是先纵向再横向,但最后我们都是往右下角推进的,都是符合要求的,所以对于这个题来说,先遍历哪个都是可取的。

46. 携带研究材料(第六期模拟笔试) (kamacoder.com)

是的小明是一位科学家但是不重要,因为这就是一个标准的动态规划的背包问题,让我们开始做吧。

#include<iostream>
#include<vector>
using namespace std;
int main(){int n,zooms;cin>>n>>zooms;vector<int> weights(n);for(int i=0;i<n;++i){cin>>weights[i];}vector<int> values(n);for(int i=0;i<n;++i){cin>>values[i];}vector<vector<int>> dp(n,vector<int>(zooms+1,0));for(int j=weights[0];j<=zooms;++j){dp[0][j]=values[0];}for(int i=1;i<n;++i){for(int j=0;j<=zooms;++j){if(j<weights[i])dp[i][j]=dp[i-1][j];else dp[i][j]=max(dp[i-1][j],dp[i-1][j-weights[i]]+values[i]);}}cout<<dp[n-1][zooms]<<endl;return 0;
}

这个题需要注意的一点是:我们讨论物品的时候是根据下标来的,是从0开始的,也就是物品有n种,但是我们遍历只遍历到n-1;而容量是从1开始的,也就是我们得从1遍历到具体的容量值,而同样的我们返回的也得是dp[n-1][zooms]才可。

虽然我们的分析已经完成,但是并非没有可以改善之处。比如我们其实不难发现我们的现在的遍历的j都是从0开始,去判断当前j和weights[i]的关系。但实际上,我们还有更聪明的做法:

dp[i][j]=max(dp[i-1][j],dp[i-1][j-weights[i]]+values[i])这是我们的递推公式,但是我们可以注意到的是,dp[i-1][j]就是位于dp[i][j]的正上方,也就是说其实我们更多地只是在看我们的另一项,否则我们会直接继承dp[i-1][j],那么这个时候我们就可以选择不用i来记录每一个这个数,而是将i这个维度去掉来不断更新我们的dp[j]达到相同的效果:

这样我们的递推公式就变成了:dp[j]=max(dp[j],dp[j-weights[i]]-values[i])。可以看到我们的数组一下就变成了一个一维数组,这样无疑大大减小我们的空间复杂度,也更清晰明了。

让我们再重复一遍我们的动态规划的步骤:

首先确定dp数组的含义,对于一维数组dp[j]来说,显然dp[j]代表背包容量为j时能填充的最大价值。

递推公式,已知是dp[j]=max(dp[j],dp[j-weights[i]]-values[i])。

然后是初始化,对于dp[0]来说,显然等于0。

遍历顺序,这个是背包问题中最值得讲究的点:我们一般来说都是循环的顺序都是先遍历物品再遍历背包容量,这个在一维数组的情况也适用。然后是我们关于物品和背包的遍历方式,物品我们依然还是从下标为0开始遍历到n-1,但是我们的背包容量遍历就必须要反过来,也就是:

for(int j=zooms;j>=weights[i];--j)为什么呢?因为我们的dp[j]是完全由dp[j]与dp[j-weights[i]]+values[i]来递推的,对于i来说并没有专门记录,如果从0开始遍历到zooms,我们很可能会反复添加一个物品(比如背包容量为2,可以装两次重量为1的物体),导致违背了0-1背包的一个物体只能使用一次的原则。而反着来遍历的话,我们其实是从大往小遍历,只要题目设计合理,我们就可以避免这个问题。

让我们再用一维数组的方式做一遍携带研究材料吧:

#include<iostream>
#include<vector>
using namespace std;
int main(){int n,zooms;cin>>n>>zooms;vector<int> weights(n);for(int i=0;i<n;++i){cin>>weights[i];}vector<int> values(n);for(int i=0;i<n;++i){cin>>values[i];}vector<int> dp(zooms+1,0);for(int i=0;i<n;++i){for(int j=zooms;j>=weights[i];--j){dp[j]=max(dp[j],dp[j-weights[i]]+values[i]);}}cout<<dp[zooms]<<endl;return 0;
}

416. 分割等和子集 - 力扣(LeetCode)

这个题乍一看可能还挺难想到是用动态规划来做,但是随着我们的思路慢慢一路顺延其实很自然地就能想到。

首先我们要求将数组分割成两个元素和相等的子集,那么我们的第一层尝试自然是求数组的总和后整除2,如果都不能整除成功就可以直接返回false。然后就是我们需要尝试将数组的一个个元素塞进一个数组中,要求这个数组的和为我们大数组的总和的一半。是不是有一种既视感?是的,其实我们的容量就是这个总和的一半,大数组里的数字就是我们的value。

class Solution {
public:bool canPartition(vector<int>& nums) {int sum=accumulate(nums.begin(), nums.end(), 0);if(sum%2!=0)return false;int target=sum/2;vector<int> dp(target+1,0);for(int i=0;i<nums.size();++i){for(int j=target;j>=nums[i];--j){dp[j]=max(dp[j],dp[j-nums[i]]+nums[i]);}}return dp[target]==target;}
};

第一步:dp数组的含义:dp[i]代表容量为i的背包中能包含的最大和。

第二步:递推公式:dp[i]=max(dp[i],dp[i-nums[i]]+nums[i]),这里我们的物体的重量和价值是一样的。但是重量是重量,价值是价值,概念上不可以混淆。

第三步,初始化,全部初始化为0即可。

第四步,确定递推顺序,这个我们在之前的一维数组部分已经讲解了。

相关文章:

代码随想录-训练营-day30

今天我们要进入动态规划的背包问题&#xff0c;背包问题也是一类经典问题了。总的来说可以分为&#xff1a; 今天让我们先来复习0-1背包的题目&#xff0c;这也是所有背包问题的基础。所谓的0-1背包问题一般来说就是给一个背包带有最大容量&#xff0c;然后给一个物体对应的需要…...

全平台搭载旭日5!科沃斯GOAT智能割草机器人全新系列正式开售

要闻 近日&#xff0c;科沃斯全新发布的GOAT A Series 和 GOAT O Series割草机器人&#xff0c;将在多国市场正式上市发售。作为业界最强的割草机器人产品之一&#xff0c;GOAT致力为割草机带来基于机器人视觉的专业定位解决方案。科沃斯GOAT全新系列产品全平台搭载地瓜机器人…...

Bob the Canadian

1&#xff1a;around the house Hi! Bob the Canadian here! Let’s learn English around the house. Come on in! Hi, Bob the Canadian here. Welcome to this video. If this is your first time here, don’t forget to click the subscribe button below, and give…...

RocketMQ与kafka如何解决消息积压问题?

前言 消息积压问题简单来说&#xff0c;就是MQ存在了大量没法快速消费完的数据&#xff0c;造成消息积压的原因主要在于“进入的多&#xff0c;消费的少”&#xff0c;或者生产的速度过快&#xff0c;而消费速度赶不上&#xff0c;基于这一问题&#xff0c;我们主要介绍如何通过…...

Node.js中Express框架使用指南:从入门到企业级实践

目录 一、Express快速入门 1. 项目初始化 2. 基础服务搭建 3. 添加热更新 二、核心功能详解 1. 路由系统 动态路由参数 路由模块化 2. 中间件机制 自定义中间件 常用官方中间件 3. 模板引擎集成 三、企业级最佳实践 1. 项目结构规范 2. 错误处理方案 3. 安全防护…...

自定义组件数据监听器案例,纯数据字段,自定义组件生命周期,页面的生命周期,插槽

1.自定义组件数据监听器案例 1.1基础案例模板 1.2定义button事件的处理函数 1.3监听对象中属性的变化&#xff0c;并且为fullColor赋值 使用通配符监听所有属性变化 2.自定义组件的纯数据字段 、 3.自定义组件的生命周期 4.组件所在页面的生命周期 5.自定义组件插槽 5.1单个插…...

mybatis-lombok工具包介绍

Lombok是一个实用的]ava类库&#xff0c;能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法&#xff0c;并可以自动化生成日志变量&#xff0c;简化java开发、提高效率。 使用前要加入Lombok依赖...

LDO技术:线性调整率与负载调整率全解析

LDO(Low Dropout Regulator)低压差线性稳压器&#xff0c;其结构比较简单、纹波和噪声比DCDC小、成本也优于DCDC&#xff0c;缺点是在输入电压和输出电压的压差比较大时&#xff0c;效率低些&#xff0c;但在小电流电源电路上被广泛使用。现在输入电压和输出电压的压差可做到10…...

SpringBoot 集成 Caffeine 实现本地缓存

目录 1、Caffeine 简介 1.1、Caffeine 简介1.2、对比 Guava cache 的性能主要优化项1.3、常见的缓存淘汰算法1.4、SpringBoot 集成 Caffeine 两种方式 2、SpringBoot 集成 Caffeine 方式一 2.1、缓存加载策略 2.1.1、手动加载2.1.2、自动加载【Loading Cache】2.1.3、异步加载…...

AF3 from_pdb_string和from_mmcif_string函数解读

AlphaFold3的from_pdb_string和from_mmcif_string函数分别用来解析蛋白质PDB和mmCIF 格式结构数据并转换为 Protein 数据类。它通过 Biopython 提供的 PDBParser 和 MMCIFParser 解析 PDB/mmCIF 文件,再通过调用_from_bio_structure函数从 Biopython 解析出的 Structure 提取 …...

【练习】图论

F. Friendly Group 图中选择一个点-1 边两端点都选择1 边一个端点选择-1 添加链接描述 #include<iostream> using namespace std; #include<vector> #include<cstring> const int N300010; int n,m; vector<int> G[N]; int temp1,temp2; bool vis[N…...

2025-02-15 禅修-若分别性,离尘无体,斯则前尘分别影事

摘要: 心执着于外镜&#xff0c;诸多境界&#xff0c;贪婪&#xff0c;嗔恨&#xff0c;痴愚&#xff0c;见诸多境界&#xff0c;诸多历练&#xff0c;被外物所扰&#xff0c;心迷性乱。将外部诸多事物&#xff0c;诸多境象&#xff0c;反而认为是自己的一部分。外部一切变动无…...

使用EVE-NE-锐捷实现NAT+ACL服务限制

一、项目拓扑 二、项目实现 1.NET配置 点击左侧的NetWorks,设置与图相同的配置&#xff0c;实现实验环境桥接到物理网络 2.GW配置 进入特权模式 enable进入全局模式 configure terminal 更改名称为GW hostname GW进入g0/0接口 interface g0/0将g0/0接口IP地址配置为192.168.…...

变相提高大模型上下文长度-RAG文档压缩-2.带早停机制的map-refine

我试过用map-refine方法来精炼上下文&#xff0c;由于它是线性的&#xff0c;运行时间随着文档数量线性增长。所以可以考虑通过判断上下文是否可以满足QA来提前结束过程。 import os import json from langchain_core.documents import Documentdata [] file_path ./data/da…...

大模型训练为什么依赖GPU

近年来&#xff0c;随着人工智能技术的飞速发展&#xff0c;特别是深度学习领域的进步&#xff0c;大模型的训练逐渐成为研究和工业界的热点。作为大模型训练中的核心硬件&#xff0c;GPU&#xff08;图形处理单元&#xff09;扮演了至关重要的角色。那么&#xff0c;为什么大模…...

二叉树链式结构:数据结构中的灵动之舞

目录 前言 一、 前置说明 二、二叉树的遍历 2.1前序遍历 2.2中序遍历 2.3 后序遍历 2.4层序遍历 三、二叉树的遍历的应用 3.1二叉树节点个数&#xff1a; 3.2二叉树的高度 3.3 二叉树第k层的节点的个数 3.4二叉树的查找 总结 前言 在数据结构的世界里&#xff0c;二叉…...

【kafka系列】Kafka如何保证消息不丢失?

目录 1. 生产者端&#xff1a;确保消息成功发送到Broker 核心机制&#xff1a; 关键步骤&#xff1a; 2. Broker端&#xff1a;持久化与副本同步 核心机制&#xff1a; 关键源码逻辑&#xff1a; 3. 消费者端&#xff1a;可靠消费与Offset提交 核心机制&#xff1a; 关…...

新建github操作

1.在github.com的主页根据提示新建一个depository。 2.配置用户名和邮箱 git config --global user.name "name" git config --global user.email "email" 3.生成ssh秘钥 ssh-keygen -t rsa 找到public key 对应的文件路径 cat /root/.ssh/id_rsa 复制显…...

第 15 天:数据存储,打造存档 读取系统!

&#x1f3af; 目标&#xff1a; ✅ 掌握 UE5 SaveGame 存档系统 ✅ 在 C 创建存档类&#xff0c;存储游戏数据 ✅ 实现存档 & 读取功能&#xff0c;让游戏状态可持久化 ✅ 在 BP_PlayerCharacter 里实现&#xff1a; * 游戏开始时自动加载存档 * 玩家受到伤害时自动存档 …...

Flutter 异步编程利器:Future 与 Stream 深度解析

目录 一、Future&#xff1a;处理单次异步操作 1. 概念解读 2. 使用场景 3. 基本用法 3.1 创建 Future 3.2 使用 then 消费 Future 3.3 特性 二、Stream&#xff1a;处理连续异步事件流 1. 概念解读 2. 使用场景 3. 基本用法 3.1 创建 Stream 3.2 监听 Stream 3.…...

Java短信验证功能简单使用

注册登录阿里云官网&#xff1a;https://www.aliyun.com/ 搜索短信服务 自己一步步申请就可以了 开发文档&#xff1a; https://next.api.aliyun.com/api-tools/sdk/Dysmsapi?version2017-05-25&languagejava-tea&tabprimer-doc 1.引入依赖 <dependency>…...

React进阶之React核心源码解析(一)

React核心源码解析 react 特点CPU卡顿IO 卡顿 新老 react 架构对比v15v16.8Scheduler 调度器Reconciler 协调器 React fiber原理更新dommount 构建过程 render阶段 — scheduler reconcilerreact源码解析react-domreact-dom/src/client/ReactDOMRoot.js react-reconcilerreact-…...

【Vue】打包vue3+vite项目发布到github page的完整过程

文章目录 第一步&#xff1a;打包第二步&#xff1a;github仓库设置第三步&#xff1a;安装插件gh-pages第四步&#xff1a;两个配置第五步&#xff1a;上传github其他问题1. 路由2.待补充 参考文章&#xff1a; 环境&#xff1a; vue3vite windows11&#xff08;使用终端即可&…...

类加载机制及双亲委派模型

一、引言 二、类加载流程 1. 加载 2. 连接 2.1 验证 2.2 准备 2.3 解析 3. 初始化 三、类加载器 类加载器的类型 双亲委派模型 打破双亲委派模型 双亲委派模型优点 一、引言 在 Java 的运行机制中&#xff0c;类加载是一个至关重要的环节。它不仅决定了 Java 程序的动态…...

tcp/ip协议设置参数,tcp/ip协议6设置

TCP/IP协议设置参数主要涉及到IP地址、子网掩码、网关地址以及DNS服务器地址等关键参数。这些参数的配置确保了网络设备能够正确地接入互联网并与其他设备进行通信。以下是对这些参数设置的详细说明&#xff1a; 1. IP地址 定义&#xff1a;IP地址是互联网中用于唯一标识每一…...

如何在Java EE中使用标签库?

在Java EE&#xff08;现在称为Jakarta EE&#xff09;中使用标签库&#xff08;Tag Library&#xff09;&#xff0c;主要是通过JSP标准标签库&#xff08;JSTL&#xff09;或自定义标签库来实现的。标签库允许在JSP页面中使用自定义的标签&#xff0c;从而简化页面逻辑、增强…...

【java】方法的基本内存原理(栈和堆)

java内存主要分为栈和堆&#xff0c;方法相关的部分主要在栈内存里&#xff0c;每个方法调用时会在栈里创建一个栈帧&#xff0c;存放局部变量和方法执行的信息。执行完后栈帧被销毁&#xff0c;局部变量消失。而对象实例存在堆里&#xff0c;由垃圾回收器管理。 **Java方法内…...

今日AI和商界事件(2025-02-15)

根据2025年2月15日的科技动态&#xff0c;以下是今日AI领域的重要事件及相关进展总结&#xff1a; 1. DeepSeek日活突破3000万&#xff0c;开源生态加速AI普惠 里程碑意义&#xff1a;开源大模型DeepSeek宣布日活跃用户数突破3000万&#xff0c;其R1模型凭借开源策略和低成本优…...

尚硅谷课程【笔记】——大数据之Hadoop【一】

课程视频链接&#xff1a;尚硅谷Hadoop3.x教程 一、大数据概论 1&#xff09;大数据概念 大数据&#xff08;Big Data&#xff09;&#xff1a;指无法再一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合&#xff0c;是需要新处理模式才能具有更强的决策力、洞察发…...

SQL 建表语句详解

SQL 建表语句详解 在 SQL 中&#xff0c;创建表&#xff08;Table&#xff09;是数据库设计的基础。表是存储数据的基本单位&#xff0c;每个表由行和列组成。创建表的过程涉及到定义表的结构&#xff0c;包括列名、数据类型、约束等。本文将详细介绍 SQL 中的建表语句&#x…...