代码随想录训练营Day29 | 01背包问题 - 416. 分割等和子集 - 494. 目标和 - 2915. 和为目标值的最长子序列的长度

01背包问题

  • 题目链接:01背包问题
  • 思路:
    1. 01背包问题是经典的题目,w[i]表示第i个物品重量,v[i]表示第i个物品价值,很容易想到在思考是,我们需要记录三种状态,当前背包装的数量,当前背包空间,当前背包装的总价值,我们用dfs(i, j)来表示,记录状态之后其余就是在这种情况下对剩下可选的物品进行装包,如果当前物品可装背包就可以得到一个递推公式
      d f s ( i , j ) = { d f s ( i − 1 , j ) , j < w [ i ] m a x ( d f s ( i − 1 , j ) , d f s ( i , j − w [ i ] ) + v [ i ] ) , j > = w [ i ] dfs(i,\ j) = \begin{cases} dfs(i-1,\ j),\ j < w[i] \\ max( dfs(i-1,\ j),\ dfs(i,\ j - w[i]) \ + \ v[i]), j >= w[i] \end{cases} dfs(i, j)={dfs(i1, j), j<w[i]max(dfs(i1, j), dfs(i, jw[i]) + v[i]),j>=w[i]
    2. 根据上述递推公式,可以使用动态规划算法来模拟dfs(i, j) 这个选择过程,使用递归搜索+记忆化,然后转成递推,最后对递推进行优化;
  • 代码:
#include <iostream>
#include <vector> 
using namespace std;int main() {int m, n;cin >> m  >> n;vector<int> w(m);vector<int> v(m);for(int i = 0; i < m; ++i) {cin >> w[i];}for(int i = 0; i < m; ++i) {cin >> v[i];}// 递归+记忆化 搜索,Kama网这种做法会内存超限vector<vector<int>> memo(m, vector<int>(n + 1, -1));auto dfs = [&](auto&& dfs, int i, int j) -> int {if(i < 0)return 0;int& res = memo[i][j];if(res != -1)return res;if(j < w[i]) {return res = dfs(dfs, i - 1, j);}return res = max(dfs(dfs, i - 1, j), dfs(dfs, i, j - w[i]) + v[i]);};//cout << dfs(dfs, m - 1, n) << endl;    // 二维dp,将记忆化搜索转为递推,dfs(i, j) 使用数组dp[i][j]表示vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));for(int i = 1; i <= m; ++i) {for(int j = 1; j <= n; ++j) {if(j >= w[i-1]) {dp[i][j] = max(dp[i-1][j], dp[i-1][j - w[i-1]] + v[i-1]);} elsedp[i][j] = dp[i-1][j];}}// cout << dp[m][n] << endl;    // 递推优化,f[n]表示n空间大小能够填充的最大价值,f[n] = max(f[n], f[n-w[i]] + v[i]);vector<int> f(n + 1, 0);for(int i = 0; i < m; ++i) {for(int j = n; j >= w[i]; --j) { // 从后往前遍历,防止选择重复f[j] = max(f[j], f[j - w[i]] + v[i]);}}cout << dp[n] << endl; return 0;     
}

416. 分割等和子集

  • 题目链接:416. 分割等和子集
  • 思路:
    1. 根据题意,需要从数组中选取n个数,n个数的和要刚好是数组和的一半,思路和0 1 背包一致,数就是物品,数的值就是价值,使用dp[i][j] 表示从i个数选择的和为j的可能性,如此得到递推公式
      d p [ i , j ] = { d p [ i − 1 , j ] , j < n u m [ i ] d p [ i − 1 , j ] ∣ ∣ d p [ i , j − n u m s [ i ] ] , j > = n u m s [ i ] dp[i,\ j] = \begin{cases} dp[i-1,\ j],\ j < num[i] \\ dp[i-1,\ j] \ || \ dp[i,\ j - nums[i]], j >= nums[i] \end{cases} dp[i, j]={dp[i1, j], j<num[i]dp[i1, j] ∣∣ dp[i, jnums[i]],j>=nums[i]
      当 j 比nums[i] 小时,nums[i]不可选故dp[i][j]的值就和dp[i-1][j]一致,j >= nums[i]时,可选可不选,故dp[i][j] = dp[i-1][j] || dp[i][j-nums[i]] 为二者的异或值
  • 代码:
class Solution {
public:// 二维递推bool f1(vector<int>& nums) {int sum = reduce(nums.begin(), nums.end()), n = nums.size();if(sum & 1)return false;sum /= 2;// 二维递推 vector<vector<int>> dp(n + 1, vector<int>(sum + 1, 0));dp[0][0] = 1; // 和为0,选取的数为0的情况算是一种情况for(int i = 1; i <= n; ++i) {int x = nums[i - 1];for(int j = 0; j <= sum; ++j) {if(j >= x)dp[i][j] = dp[i-1][j - x] || dp[i-1][j];else dp[i][j] = dp[i-1][j];}}return dp[n][sum];}// 二维递推优化成一维,dp[sum]表示何为sum的可能性 dp[sum] = dp[sum] || dp[sum - nums[i]]bool canPartition(vector<int>& nums) {vector<int> dp(sum + 1, 0);dp[0] = 1; // 和为0算一种情况for(int i = 1; i <= n; ++i) {int x = nums[i - 1];for(int j = sum; j >= x; --j) { // 这里和0 1 背包类似,从后往前遍历防止重复选择dp[j] = dp[j] || dp[j - x];if(dp[sum]) // 提前判断return dp[sum];}}return dp[sum];}
};

494. 目标和

  • 题目链接:494. 目标和
  • 思路:
    1. 本题需要转换一下,由题意可知,数组中一部分数要转为负数,设选择过程中,数组和为sum,选择的正数和为 x,选择负数的绝对值和为 y,那么就有以下公式
      x + y = s u m x − y = t a r g e t ⇓ { x = s u m + t a r g e t 2 y = s u m − t a r g e t 2 x + y = sum\\ x - y = target \\ \Downarrow \\ \begin{cases} x = \frac{sum \ +\ target}{2} \\ y = \frac{sum \ -\ target}{2} \\ \end{cases} x+y=sumxy=target{x=2sum + targety=2sum  target
      故本题的思路是,选择x,y满足上述等式条件即可,知道sum和target,可以算出x,y,剩下的思路就是和分割等和子集类似了,不过这里的和是x或者y,然后这个过程记录组合数量即可
    2. 本题还需要一个注意的地方,就是target可以为正也可以为负
      当target >= 0 时,选择 y = s u m − t a r g e t 2 y = \frac{sum \ -\ target}{2} y=2sum  target,这样选择y,递推过程就会变少
      当target < 0 时, 选择 x = s u m + t a r g e t 2 x = \frac{sum \ +\ target}{2} x=2sum + target,这样选择x,递推过程就会变少
      综上,选择 x = s u m − ∣ t a r g e t ∣ 2 x = \frac{sum \ -\ |target|}{2} x=2sum  target,不管target,为正还是负,都可以选择到最小的数。
    3. 思路分析完之后,递推公式和分割等和子集一样,不过这里不是记录可行性,记录组合数目,递推公式如下
      d p [ i ] [ j ] = { d p [ i − 1 ] [ j ] , j < n u m [ i ] d p [ i − 1 ] [ j ] + d p [ i ] [ j − n u m s [ i ] ] , j > = n u m s [ i ] dp[i][j] = \begin{cases} dp[i-1][j],\ j < num[i] \\ dp[i-1][j] \ + \ dp[i][j - nums[i]], j >= nums[i] \end{cases} dp[i][j]={dp[i1][j], j<num[i]dp[i1][j] + dp[i][jnums[i]],j>=nums[i]
  • 代码
class Solution {
public:// 二维递推公式如下int f1(vector<int>& nums, int target) {int s = reduce(nums.begin(), nums.end()) - abs(target);if (s < 0 || s % 2) {return 0;}int m = s / 2; // 背包容量int n = nums.size();vector<vector<int>> dp(n + 1, vector<int>(m + 1));dp[0][0] = 1;for (int i = 0; i < n; i++) {for (int c = 0; c <= m; c++) {if (c < nums[i]) {dp[i + 1][c] = dp[i][c]; // 只能不选} else {dp[i + 1][c] = dp[i][c] + dp[i][c - nums[i]]; // 不选 + 选}}}return f[n][m];}// 二维递推优化,一维递推int findTargetSumWays(vector<int>& nums, int target) {int n  = nums.size(), sum = reduce(nums.begin(), nums.end()) - abs(target);if(sum < 0 || sum % 2) // 判断可行性,不能整除2 带表没有符合题意的x 或者yreturn 0;int q = sum  / 2;  // 求出x 或 y 中的最小值// 优化一维递推 dp[sum] = dp[sum] + dp[sum - num[i]]vector<int> dp(q + 1);dp[0] = 1;for(int x : nums) {for(int j = q; j >= x; --j) {dp[j] += dp[j - x];}}return dp[q];}
};

2915. 和为目标值的最长子序列的长度

  • 题目链接:2915. 和为目标值的最长子序列的长度
  • 思路:
    1. 本题思路和分割等和子集那题类似,这找的是符合和为target的序列的最大长度,故使用dp[i][j]记录 长度 i 和为 j的最大子序列长度可得递推公式
      d p [ i ] [ j ] = { d p [ i − 1 ] [ j ] , j < n u m [ i ] m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − n u m s [ i ] ] + 1 ) , j > = n u m s [ i ] dp[i][j] = \begin{cases} dp[i-1][j],\ j < num[i] \\ max(dp[i-1][j] \ , \ dp[i][j - nums[i]] + 1), j >= nums[i] \end{cases} dp[i][j]={dp[i1][j], j<num[i]max(dp[i1][j] , dp[i][jnums[i]]+1),j>=nums[i]
  • 代码:

class Solution {
public:// 二维递推公式法int f1(vector<int>& nums, int target) {vector<vector<int>> dp(n + 1, vector<int>(target + 1, INT_MIN / 2)); // 初始化dp数组,这里要比较最大长度,故失败的初始化为 INT_MIN / 2dp[0][0] = 0; // 长度和最终达到 0 时,代表这种情况符合,初始化为0for(int i = 0; i < n; ++i) {int x = nums[i];for(int j = 0; j <= target; ++j) {if(j >= x)dp[i+1][j] = max(dp[i][j], dp[i][j - x] + 1); elsedp[i+1][j] = dp[i][j];}}}// 一维递推公式法 dp[sum] = max(dp[sum], dp[sum - nums[i]] + 1);int lengthOfLongestSubsequence(vector<int>& nums, int target) {int n = nums.size();vector<int> dp(target + 1, INT_MIN / 2);  // 初始化一维dp数组dp[0] = 0;int s = 0;for(int x : nums) {int s = min(s + x, target); // 优化,遍历当前能达到的最大的和for(int j = s; j >= x; --j) { // 从后往前开始遍历,防止重复选择dp[j] = max(dp[j], dp[j - x] + 1);}}return dp[target] < 0 ? -1 : dp[target];}
};

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

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

相关文章

数据结构(Java版)第二期:包装类和泛型

目录 一、包装类 1.1. 基本类型和对应的包装类 1.2. 装箱和拆箱 1.3. 自动装箱和自动拆箱 二、泛型的概念 三、引出泛型 3.1. 语法规则 3.2. 泛型的优点 四、类型擦除 4.1. 擦除的机制 五、泛型的上界 5.1. 泛型的上界的定义 5.2. 语法规则 六、泛型方法 6.1…

敬请关注:CEPGT 2024 新增主讲

Prof. Marc A. Rosen, Ontario Tech University, Canada 曾担任安大略省理工大学工程与应用科学学院创始院长、加拿大工程学院院长和加拿大机械工程学会会长。 他的主要研究领域是能源、热力学、可持续发展等。Google Scholar Citations 48000余次&#xff0c;H指数98。Prof. …

【Python】30个Python爬虫的实战项目!!!(附源码)

Python爬虫是数据采集自动化的利器。本文精选了30个实用的Python爬虫项目&#xff0c;从基础到进阶&#xff0c;每个项目都配有完整源码和详细讲解。通过这些项目的实战&#xff0c;可以全面掌握网页数据抓取、反爬处理、并发下载等核心技能。 一、环境准备 在开始爬虫项目前…

如何编译 Cesium 源码

如何编译 Cesium 源码 Cesium 是一个开源的 JavaScript 库&#xff0c;用于构建 3D 地球和地图应用程序。它提供了一套强大的 API 和工具&#xff0c;使开发者能够创建丰富的地理空间应用。本文将指导您如何从 GitHub 下载 Cesium 源码&#xff0c;并在本地进行编译。 TilesB…

计算服务器定制化,计算力提升的关键!

如今&#xff0c;计算服务器的性能、成本、灵活性以及可靠性等因素对于企业的运营和发展起着至关重要的作用。定制服务器&#xff0c;作为一种根据企业特定需求和业务特点专门设计制造的服务器解决方案&#xff0c;正逐渐成为众多企业的明智之选。 对于计算服务器而言&#xff…

51WORLD与南京水利研究院联合研发,国产数字孪生超融合一体机

近日&#xff0c;太湖流域水治理国际会议在江苏省无锡市举行。大会由水利部国际合作与科技司、河湖管理司、中国水利学会、水利部太湖流域管理局、无锡市人民政府、中国交通建设集团有限公司指导&#xff0c;南京水利科学研究院主办&#xff0c;以“践行新发展理念、推进流域水…

STL关联式容器之map

map的特性是&#xff0c;所有元素都会根据元素的键值自动被排序。map的所有元素都是pair&#xff0c;同时拥有实值(value)和键值(key)。pair的第一元素被视为键值&#xff0c;第二元素被视为实值。map不允许两个元素拥有相同的键值。下面是<stl_pair.h>中pair的定义 tem…

python小课堂(一)

基础语法 1 常量和表达式2 变量和类型2.1 变量是什么2.2 变量语法 3 变量的类型3.1 动态类型特性 4 注释4.1注释是什么 5 输入输出5.1 print的介绍5.2 input 6 运算符6.1 算术运算符在这里插入图片描述6.2 关系运算符6.3 逻辑运算符6.4赋值运算符 1 常量和表达式 在print()中可…

Qt:信号槽

一. 信号槽概念 信号槽 是 Qt 框架中一种用于对象间通信的机制 。它通过让一个对象发出信号&#xff0c;另一个对象连接到这个信号的槽上来实现通信。信号槽机制是 Qt 的核心特性之一&#xff0c;提供了一种灵活且类型安全的方式来处理事件和数据传递。 1. 信号的本质 QT中&a…

高质量代理池go_Proxy_Pool

高质量代理池go_Proxy_Pool 声明&#xff01; 学习视频来自B站up主 ​泷羽sec​​ 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章 笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以…

Spring Cloud Data Flow快速入门Demo

1.什么是Spring Cloud Data Flow&#xff1f; Spring Cloud Data Flow 是一个用于构建和编排数据处理流水线的云原生框架。它提供了一种简化的方式来定义、部署和管理数据处理任务和流应用程序。以下是一些关键特性和组件&#xff1a; 关键特性 流处理&#xff1a; 支持实时数…

CCE-基础

背景&#xff1a; 虚拟化产生解决物理机资源浪费问题&#xff0c;云计算出现实现虚拟化资源调度和管理&#xff0c;容器出现继续压榨虚拟化技术产生的资源浪费&#xff0c;用命名空间隔离&#xff08;namespace&#xff09; 灰度升级&#xff08;升级中不影响业务&#xff09…

[免费]SpringBoot+Vue毕业设计论文管理系统【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue毕业设计论文管理系统&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue毕业设计论文管理系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 现代经济快节奏发展以及不断完善升级的信…

udp_socket

文章目录 UDP服务器封装系统调用socketbind系统调用bzero结构体清0sin_family端口号ip地址inet_addrrecvfromsendto 新指令 netstat -naup (-nlup)包装器 的两种类型重命名方式包装器使用统一可调用类型 关键字 typedef 类型重命名系统调用popen关于inet_ntoa UDP服务器封装 系…

三极管工作原理,以及小电流,如何驱动大电流

因为研究【自动下载电路实现】&#xff0c;涉及到三极管内容&#xff0c;之前看过&#xff0c;现在回看之前的笔记&#xff0c;一点印象都没了&#xff0c;于是&#xff0c;想了个办法&#xff0c;记住它 个人联想&#xff0c;不喜绕道&#xff0c;只是帮助个人记忆的 标题也是…

干货 | WIFI7和WIFI6区别简单介绍

1、传输标准 WIFI 6使用的是11ax标准WIFI 7使用的是11be标准 2、编码方式及带宽 WIFI6使用了1024-QAM调制方式&#xff0c;将每个数据符号编码为10位。WIFI7使用了更高阶的4096-QAM&#xff0c;将每个符号编码为12位&#xff0c;提高了单位时间内的数据传输量。虽然更高阶的调…

React基础知识一

写的东西太多了&#xff0c;照成csdn文档编辑器都开始卡顿了&#xff0c;所以分篇写。 1.安装React 需要安装下面三个包。 react:react核心包 react-dom:渲染需要用到的核心包 babel:将jsx语法转换成React代码的工具。&#xff08;没使用jsx可以不装&#xff09;1.1 在html中…

对象存储访问管理

一、前言 对象存储是一种以对象为中心的存储方式&#xff0c;将数据存储为对象而不是文件&#xff0c;在对象存储中&#xff0c;每个对象都有唯一的标识符&#xff0c;这个标识符是由系统自动生成的。与传统文件系统不同&#xff0c;对象存储中不需要使用文件夹或路径来查找对…

【Java】二叉树:数据海洋中灯塔式结构探秘(上)

个人主页 &#x1f339;&#xff1a;喜欢做梦 二叉树中有一个树&#xff0c;我们可以猜到他和树有关&#xff0c;那我们先了解一下什么是树&#xff0c;在来了解一下二叉树 一&#x1f35d;、树型结构 1&#x1f368;.什么是树型结构&#xff1f; 树是一种非线性的数据结构&…

Lucene(2):Springboot整合全文检索引擎TermInSetQuery应用实例附源码

前言 本章代码已分享至Gitee: https://gitee.com/lengcz/springbootlucene01 接上文。Lucene(1):Springboot整合全文检索引擎Lucene常规入门附源码 如何在指定范围内查询。从lucene 7 开始&#xff0c;filter 被弃用&#xff0c;导致无法进行调节过滤。 TermInSetQuery 指定…