代码随想录-训练营-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即可。

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

百问网(100ask)提供的烧写工具的原理和详解;将自己编译生成的u-boot镜像文件烧写到eMMC中

百问网(100ask)提供的烧写工具的原理 具体的实现原理见链接 http://wiki.100ask.org/100ask_imx6ull_tool 为了防止上面这个链接失效&#xff0c;我还对上面这个链接指向的页面保存成了mhtml文件&#xff0c;这个mhtml文件的百度网盘下载链接&#xff1a; https://pan.baidu.c…

【旋转框目标检测】基于YOLO11/v8深度学习的遥感视角船只智能检测系统设计与实现【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

侯捷 C++ 课程学习笔记:C++ 面向对象开发的艺术

在侯捷老师的 C 系列课程中&#xff0c;《C 面向对象开发》这门课程让我对面向对象编程有了更深入的理解。面向对象编程&#xff08;OOP&#xff09;是现代软件开发中最重要的编程范式之一&#xff0c;而 C 作为支持 OOP 的语言&#xff0c;提供了强大的工具和特性。侯捷老师通…

神经网络常见激活函数 12-Swish函数

Swish 函数导函数 Swish函数 S w i s h ( x ) x ⋅ σ ( β x ) x 1 e − β x \begin{aligned} \rm Swish(x) & x \cdot \sigma(\beta x) \\ & \frac{x}{1 e^{-\beta x}} \end{aligned} Swish(x)​x⋅σ(βx)1e−βxx​​ Swish函数导数 d d x S w i s h ( x…

CF 137B.Permutation(Java 实现)

题目分析 输入n个样本&#xff0c;将样本调整为从1到n的包含&#xff0c;需要多少此更改 思路分析 由于样本量本身就是n&#xff0c;无论怎么给数据要么是重复要么不在1到n的范围&#xff0c;只需要遍历1到n判断数据组中有没有i值即可。 代码 import java.util.*;public clas…

web第三次作业

弹窗案例 1.首页代码 <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>综合案例</title><st…

go语言简单快速的按顺序遍历kv结构(map)

文章目录 需求描述用map实现按照map的key排序用二维切片实现用结构体实现 需求描述 在go语言中&#xff0c;如果需要对map遍历&#xff0c;每次输出的顺序是不固定的&#xff0c;可以考虑存储为二维切片或结构体。 假设现在需要在页面的下拉菜单中展示一些基础的选项&#xff…

Unity 命令行设置运行在指定的显卡上

设置运行在指定的显卡上 -force-device-index

分享一个使用的音频裁剪chrome扩展-Ringtone Maker

一、插件简介 铃声制作器是一个简单易用的 Chrome 扩展&#xff0c;专门用于制作手机铃声。它支持裁剪音频文件的特定片段&#xff0c;并将其下载为 WAV 格式&#xff0c;方便我们在手机上使用。无论是想从一段长音频中截取精彩部分作为铃声&#xff0c;还是对现有的音频进行个…

数据开放共享和平台整合优化取得实质性突破的智慧物流开源了

智慧物流视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;从而大大减少企业级应用约95%的开发成本可通过边缘计算技术…

预留:大数据Hadoop之——部署hadoop+hive+Mysql环境(Linux)

传送门目录 前期准备 一、JDK的安装 1、安装jdk 2、配置Java环境变量 3、加载环境变量 4、进行校验 二、hadoop的集群搭建 1、hadoop的下载安装 2、配置文件设置 2.1. 配置 hadoop-env.sh 2.2. 配置 core-site.xml 2.3. 配置hdfs-site.xml 2.4. 配置 yarn-site.xm…

《Spring实战》(第6版)第1章 Spring起步

第1部分 Spring基础 第1章 Spring起步 1.1 什么是Spring Spring的核心是提供一个容器(container)。 称为Spring应用上下文(Spring application context)。 创建和管理应用的组件(bean)&#xff0c;与上下文装配在一起。 Bean装配通过依赖注入(Dependency Injection,DI)。…

DesignCon2019 Paper分享--Automotive 芯片封装的SIPI优化

本期分享一篇intel在DesignCon2019上发表的介绍汽车芯片封装SIPI优化的paper--《Signal/Power Integrity Optimizations In An IoT Automotive Package》,文章主要介绍汽车芯片在SIPI上面临的挑战并提出了一些优化措施。 汽车芯片的发展趋势 如今&#xff0c;消费者对于车内用…

技术评测:MaxCompute MaxFrame——阿里云自研分布式计算框架的Python编程接口

引言 随着大数据和人工智能技术的发展&#xff0c;数据处理的需求日益增长。阿里云推出的MaxCompute MaxFrame&#xff08;简称“MaxFrame”&#xff09;是一个专为Python开发者设计的分布式计算框架&#xff0c;它不仅支持Python编程接口&#xff0c;还能直接利用MaxCompute的…

优选算法《位运算》

在本篇当中我们将会复习之前在C语言阶段学习的各种位运算&#xff0c;并且在复习当中将再补充一些在算法题当中没有进行总结的位运算的使用方法&#xff0c;再总结完常见的位运算使用方法之和接下来还是和之前的算法篇章一样通过几道算法题来对这些位运算的方法技巧进行巩固。在…

复旦大学:公共数据开放利用层报告(2024)

摘 要: 数据利用是公共数据开放的成效展现环节。 中国公共数据开放评估中利用层的指标体系包括利用促进、 利用多样性、 成果数量、 成果质量、成果价值 5 个一级指标。 其中, 省域评估指标体系更关注省级统筹与省市协同, 而城市评估指标体系更强调成果产出与价值释放。 根据该…

CAS单点登录(第7版)24.高可用性

如有疑问&#xff0c;请看视频&#xff1a;CAS单点登录&#xff08;第7版&#xff09; 高可用性 概述 高可用性指南 &#xff08;HA/Clustering&#xff09; 高度可用的 CAS 部署是一种提供弹性以响应各种故障模式的部署&#xff0c;以便 CAS 在发生故障时继续提供 SSO 服务…

Vue极简插件安装

1. 打开Google浏览器&#xff0c;输入网址极简插件官网_Chrome插件下载_Chrome浏览器应用商店极简插件是一个优质Chrome插件下载商店&#xff0c;收录热门好用的Chrome插件扩展&#xff0c;国内最方便的Chrome插件下载网站。一键下载谷歌扩展插件&#xff0c;无套路下载插件。h…

代码随想录刷题攻略---动态规划---子序列问题1---子序列

子序列&#xff08;不连续&#xff09;和子序列&#xff08;连续&#xff09;的问题 例题1: 最长递增子序列 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的…

3-初始化项目

在文件UIStaticHelper配置路径 YIUI自动化工具 在Tools->YIUI自动化工具即可看到面板。有6个功能&#xff0c;如下所示。 在运行的过程中&#xff0c;用绑定代替反射是因为手机运行放射是开销比较大的&#xff0c;所以用绑定代替反射&#xff0c;在发布前UI如果有改动&…