代码随想录算法训练营第三十六天|01背包问题 二维 ,01背包问题 一维 ,416. 分割等和子集

背包理论基础

01 背包(二维)

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

背包最大重量为4。

物品为:

重量价值
物品0115
物品1320
物品2430

问背包能背的物品最大价值是多少?

思路:依然是动态规划。

解决:动态规划五步曲

        1.确定dp数组及下标含义;

        dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。

        2.确定递推公式;

                考虑dp[i][j]是如何推导过来;

                ①加入第i件物品;

                        加入第i件物品后,相较于第i-1个物品,加入第i件物品后价值总和就等于dp[i-1][j-weight[i]]+value[i]

                ②第i件物品加入重量超标,不加入;

                        不加入价值总和就是放入第i-1个物品后价值总和:dp[i-1][j]

        所以dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i])

        3.确定dp数组初始化;

        首先当j=0时,也就是书包最大重量为0时,dp[i][0]=0;其次只放物品0时,背包价值总和都是15,所以dp[0][j]=15(j>weight[0])。注意这里容量要大于第一个物品的重量。

        4.确定遍历顺序;

        遍历顺序肯定是从左向右,从上到下,最后遍历到右下角。

        5.举例推导dp数组。

        

代码:

void test_2_wei_bag_problem1() {vector<int> weight={1,3,4};vector<int> value={15,20,30};int bagweight = 4;vector<vector<int>> dp(weight.size(),vector<int>(bagweight+1,0));//i是物品数量,j是背包容量//初始化for(int j=weight[0];j<=bagweight;j++){dp[0][j]=value[0];}
// 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]);}}cout << dp[weight.size() - 1][bagweight] << endl;
int main() {test_2_wei_bag_problem1();
}

 01 背包(一维)

例子:背包最大重量为4。

物品为:

重量价值
物品0115
物品1320
物品2430

问背包能背的物品最大价值是多少?

思路:对于背包问题其实状态都是可以压缩的。

在使用二维数组的时候,递推公式:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

其实可以发现如果把dp[i - 1]那一层拷贝到dp[i]上,表达式完全可以是:dp[i][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i]);

与其把dp[i - 1]这一层拷贝到dp[i]上,不如只用一个一维数组了,只用dp[j](一维数组,也可以理解是一个滚动数组)。

解决:动态规划五步曲

        1.确定dp[j]的含义;

         dp[j]表示容量为j的背包,能背的最大价值。

        2.确定递推公式;

        dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);这里还是一样可以选择放i物品或者不放。

        3.确定dp初始化;

        最开始j=0时候,装不了物品。dp[0]=0;

        4.确定遍历顺序;

        举一个例子:物品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[2]就已经是30了,意味着物品0,被放入了两次,所以不能正序遍历。        

        倒序就是先算dp[2]

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

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

        所以从后往前循环,每次取得状态不会和之前取得状态重合,这样每种物品就只取一次了

        5.举例推导公式。

代码:

void test_1_wei_bag_problem() {vector<int> weight = {1, 3, 4};vector<int> value = {15, 20, 30};int bagWeight = 4;// 初始化vector<int> dp(bagWeight + 1, 0);for(int i = 0; i < weight.size(); i++) { // 遍历物品for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);}}cout << dp[bagWeight] << endl;
}int main() {test_1_wei_bag_problem();
}

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

给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

示例 1:

输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。

示例 2:

输入:nums = [1,2,3,5]
输出:false
解释:数组不能分割成两个元素和相等的子集。

思路:这个问题如何转化成背包问题?最好的结果就是分成两个子集和相等,既然和相等,那么子集的和就是总和的一半,也就是说,从nums数组种取出元素,能够满足和等于总和的一半,那么结果就是true。那这里背包容量就是总和的一半,物品的价值就是元素数值,物品重量可以说每个都是1,也可以不用管

解决:动态规划五步曲:

        1.确定dp[i]的含义;

        j表示背包总容量,这里相当于目标值,从目标值递减遍历;背的最大重量为dp[j],当dp[j]等于目标值时说明可以分割成两个子集。

        2.确定递推公式;

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

        3.确定dp初始化;

        初始化和一维数组一样,都设置为0。

        4.确定遍历顺序;

        遍历顺序从大到小,防止重复放入。

        5.举例推导公式。

代码:

class Solution {
public:bool canPartition(vector<int>& nums) {int sum=0;for(int i=0;i<nums.size();i++){sum+=nums[i];}vector<int> dp(10001, 0);if(sum%2==1){return false;}int target=sum/2;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]);}}if (dp[target] == target) return true;return false;}
};

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

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

相关文章

Python小案例:while练习题

目录 while练习题&#xff1a;1、存款多少年能翻倍2.小球坠落长度计算3、猴子吃桃4、计算&#xff1a;1-23-4...99-100的和 while练习题&#xff1a; 1、存款多少年能翻倍 1万本金&#xff0c;年利息&#xff1a;0.0325&#xff0c;求连本带息多少年能翻倍 解析&#xff1a;…

Codeforces Round 913 (Div. 3) A~E(F,G更新中)

A.Rook&#xff08;循环&#xff09; 题意&#xff1a; 给出一个 8 8 8 \times 8 88的棋盘和一个棋子&#xff08;可以任选上下左右四方向移动任意步数&#xff09;&#xff0c;问一次移动可以到达哪些格子。 分析&#xff1a; 使用for循环对棋子所在的行列进行遍历并输出…

「智慧城市」这一概念科学吗?还是炒作?

智慧城市是一个综合性的概念&#xff0c;它利用信息技术和创新概念&#xff0c;将城市的各个系统和服务集成起来&#xff0c;以提升城市运行效率、优化城市管理和服务&#xff0c;改善市民的生活质量。 具体来说&#xff0c;智慧城市涵盖了许多领域&#xff0c;包括城市规划、建…

数据通信的基础知识

目录 一、物理层的主要功能 二、物理层的特性 三、数据通信的几个术语 四、信道的几个基本概念 1、信道 2、基带信号 &#xff08;1&#xff09;基带调制常用编码方式 1&#xff09;不归零码&#xff08;NRZ&#xff1a;Non-Return to Zero&#xff09; 2&#xff09;…

MATLAB——二维小波的多层重构

%% 学习目标&#xff1a;二维小波的多层重构 %% 案例1 clear all; close all; load woman.mat; Xind2gray(X,map); [C,S]wavedec2(X,3,db4); %二维小波的多层分解 S C(1:38*38)0; %将小波的近似系数设置为0 Ywaverec2(C,S,db4); %二维小波的多层…

MYSQL全语法速查(含示例)

文章目录 1.从简单的查询开始查找所有记录(SELECT *)查找记录中的所有登录名(SELECT)查找登录名为admin的密码(WHERE)查找电话号码非空的记录(IS NOT NULL)查找所在城市为北京或者用户名字是李四的记录(OR)查找所在城市为北京并且用户名字是张三的记录(AND)查找用户名字是李四或…

组件的生命周期

目录​ 1&#xff1a;生命周期和生命周期函数的概念 2&#xff1a;组件创建的过程 3&#xff1a;组件创建阶段beforeCreate&#xff0c;created&#xff0c;beforeMount&#xff0c;mounted生命周期函数。 3.1&#xff1a;beforeCreate方法示例&#xff1a; 3.2&#xff1…

【数据结构】动态规划(Dynamic Programming)

一.动态规划&#xff08;DP&#xff09;的定义&#xff1a; 求解决策过程&#xff08;decision process&#xff09;最优化的数学方法。 将多阶段决策过程转化为一系列单阶段问题&#xff0c;利用各阶段之间的关系&#xff0c;逐个求解。 二.动态规划的基本思想&#xff1a; …

团队git操作流程

项目的开发要求&#xff1a;&#xff08;1&#xff09;项目组厉员代码提交不少于20次 &#xff08;2&#xff09;项目组厉员每天提交不少于20次 &#xff08;3&#xff09;企业项目开发代码的每天的提交一般提交3-5次 &#xff08;4&#xff09;代码仓库的管理 git的基础操作流…

对于多台232modbus仪表低成本通讯的modbus转profinet网关

随着越来越多的仪表设备采用Modbus通信协议&#xff0c;其中又以232 Modbus仪表的应用最为广泛。而为了实现多台232 Modbus仪表低成本通信&#xff0c;Modbus转Profinet网关应运而生。Modbus转Profinet网关不仅能够实现多台仪表之间的数据传输&#xff0c;还能够保证通信的稳定…

【数据结构】——二叉树简答题模板

目录 一、树和二叉树的概念&#xff08;一&#xff09;二叉树的定义和性质&#xff08;二&#xff09;树和二叉树的区别 二、完全二叉树和满二叉树三、二叉树的遍历&#xff08;一&#xff09;由序列确定二叉树&#xff08;二&#xff09;不同遍历序列的关系 四、二叉树的性质&…

计算机操作系统3

1.虚拟机 VM 两类虚拟机的对比&#xff1a; 2.进程 进程的特征&#xff1a; 进程状态的转换&#xff08;五大状态&#xff09; 3.进程控制原语的作用 4.线程 ​​​​​线程的属性 实现方式 5.调度算法的评价指标

OpenCV-python下载安装和基本操作

文章目录 一、实验目的二、实验内容三、实验过程OpenCV-python的安装与配置python下载和环境配置PIP镜像安装Numpy安装openCV-python检验opencv安装是否成功 openCV-python的基本操作图像输入和展示以及写出openCV界面编程单窗口显示多图片鼠标事件键盘事件滑动条事件 四、实验…

【源码解析】聊聊阻塞队列之BlockingArrayQueue

阻塞队列 阻塞队列&#xff1a;顾名思义 首先它是一个队列&#xff0c;而一个阻塞队列在数据结构中所起的作用大致如下入所示。 当阻塞队列是空时&#xff0c;从队列中获取元素的操作将会被阻塞。当阻塞队列时满的时&#xff0c;往队列里添加元素的操作将会被阻塞。 试图从空的…

全球6G发展大会开幕,为什么我们需要6G

2023全球6G发展大会 由中国IMT-2030&#xff08;6G&#xff09;推进组、中国通信学会、重庆两江新区管理委员会联合主办的2023全球6G发展大会今天在重庆两江新区明月湖成功开幕&#xff0c;开幕式上发布了《6G网络架构展望》《6G无线系统设计原则和典型特征》白皮书。 《6G网络…

有向图的拓扑序列(拓扑排序)

给定一个 n 个点 m 条边的有向图&#xff0c;点的编号是 1 到 n&#xff0c;图中可能存在重边和自环。 请输出任意一个该有向图的拓扑序列&#xff0c;如果拓扑序列不存在&#xff0c;则输出 −1。 若一个由图中所有点构成的序列 A 满足&#xff1a;对于图中的每条边 (x,y)&a…

现货白银简单介绍

在贵金属投资领域&#xff0c;现货白银是当前国际上最为流行、交投最为活跃的白银投资方式&#xff0c;其交易市场遍布全球&#xff0c;包括伦敦、苏黎世、纽约、芝加哥及香港等主要市场&#xff0c;是一种以杠杆交易和做市商的形式进行的现货交易。 现货白银可以说是当下交易模…

对String类的深入理解

String类&#xff1a; String类相信大家对这个类并不陌生&#xff0c;这就是我们熟悉的字符串类型&#xff0c;但是我们一开始只知道它是用来定义字符串的&#xff0c;并不知道它的底层原理&#xff0c;这里我们就来简单的分析一下String的底层原理&#xff0c;首先我们来看一下…

Django回顾 - 6 Ajax

【1】Ajax 定义&#xff1a; 异步Javscript和XML 作用&#xff1a; Javascript语言与服务器(django)进行异步交互&#xff0c;传输的数据为XML&#xff08;当然&#xff0c;传输的数据不只是XML,现在更多使用json数据&#xff09; 同步交互和异步交互&#xff1a; 1、同步交互&…

IO多路复用(新)

1.前景回顾 无论是阻塞IO还是非阻塞IO&#xff0c;用户应用在一阶段都需要调用recvfrom来获取数据&#xff0c;差别在于无数据时的处理方案&#xff1a; 如果调用recvfrom时&#xff0c;恰好内核没有数据&#xff0c;那么阻塞IO会使用户进程阻塞&#xff0c;非阻塞IO使CPU进行空…