代码随想录算法训练营第42天 | 01背包问题理论基础 + 416.分割等和子集

今日任务

  •  01背包问题,你该了解这些! 
  •  01背包问题,你该了解这些! 滚动数组  
  •  416. 分割等和子集

01背包问题 二维数组

理论基础:代码随想录

题目链接:题目页面

    01 背包

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

    暴力解法:

        每一件物品其实只有两个状态,取或者不取,所以可以使用回溯法搜索出所有的情况
        暴力的解法是指数级别的时间复杂度。进而才需要动态规划的解法来进行优化

    二维dp数组

        1 确定dp数组及含义:

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

        2 递推公式:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])
        3 dp数组初始化:所有dp[i][0]均为0;当 j < weight[0]的时候 dp[0][j] 是 0,当j >= weight[0]时,dp[0][j] 是value[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));// 初始化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();
}

//二维dp数组实现
#include <bits/stdc++.h>
using namespace std;int n, bagweight;// bagweight代表行李箱空间
void solve() {vector<int> weight(n, 0); // 存储每件物品所占空间vector<int> value(n, 0);  // 存储每件物品价值for(int i = 0; i < n; ++i) {cin >> weight[i];}for(int j = 0; j < n; ++j) {cin >> value[j];}// dp数组, dp[i][j]代表行李箱空间为j的情况下,从下标为[0, i]的物品里面任意取,能达到的最大价值vector<vector<int>> dp(weight.size(), vector<int>(bagweight + 1, 0));// 初始化, 因为需要用到dp[i - 1]的值// j < weight[0]已在上方被初始化为0// j >= weight[0]的值就初始化为value[0]for (int j = weight[0]; j <= bagweight; j++) {dp[0][j] = value[0];}for(int i = 1; i < weight.size(); i++) { // 遍历科研物品for(int j = 0; j <= bagweight; j++) { // 遍历行李箱容量// 如果装不下这个物品,那么就继承dp[i - 1][j]的值if (j < weight[i]) dp[i][j] = dp[i - 1][j];// 如果能装下,就将值更新为 不装这个物品的最大值 和 装这个物品的最大值 中的 最大值// 装这个物品的最大值由容量为j - weight[i]的包任意放入序号为[0, i - 1]的最大值 + 该物品的价值构成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() {while(cin >> n >> bagweight) {solve();}return 0;
}

 

 

01背包问题 一维/滚动数组

理论基础:代码随想录

 题目链接:题目页面

推荐 使用一维dp数组的写法,比较直观简洁,而且空间复杂度还降了一个数量级

    在二维dp数组的基础上,其实可以把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](一维数组,也可以理解是一个滚动数组)。

    这就是滚动数组的由来,需要满足的条件是上一层可以重复利用,直接拷贝到当前层。

    滚动dp数组:

        1 dp[j]:容量为j的背包,所背的物品价值可以最大为dp[j]
        2 递推公式:dp[j]有两个选择,一个是取自己dp[j] 相当于 二维dp数组中的dp[i-1][j],即不放物品i;一个是取dp[j - weight[i]] + value[i],即放物品i,指定是取最大的

dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
  • 3 初始化:都初始为0就可以了
  • 4 遍历顺序:一维dp遍历的时候,背包是从大到小,倒序遍历是为了保证物品i只被放入一次,每次取得状态不会和之前取得状态重合,这样每种物品就只取一次了;两个嵌套for循环的顺序,先遍历物品嵌套遍历背包容量,不可颠倒
  • 5 推导dp数组:无参数版
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();
}
// 一维dp数组实现
#include <iostream>
#include <vector>
using namespace std;int main() {// 读取 M 和 Nint M, N;cin >> M >> N;vector<int> costs(M);vector<int> values(M);for (int i = 0; i < M; i++) {cin >> costs[i];}for (int j = 0; j < M; j++) {cin >> values[j];}// 创建一个动态规划数组dp,初始值为0vector<int> dp(N + 1, 0);// 外层循环遍历每个类型的研究材料for (int i = 0; i < M; ++i) {// 内层循环从 N 空间逐渐减少到当前研究材料所占空间for (int j = N; j >= costs[i]; --j) {// 考虑当前研究材料选择和不选择的情况,选择最大值dp[j] = max(dp[j], dp[j - costs[i]] + values[i]);}}// 输出dp[N],即在给定 N 行李空间可以携带的研究材料最大价值cout << dp[N] << endl;return 0;
}

416.分割等和子集 - Medium

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

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

思路: 转换成背包容易为 1/2 数组和的 01背包问题。时间复杂度:O(n^2),空间复杂度:O(n),虽然dp数组大小为一个常数,但是大常数

class Solution {
public:bool canPartition(vector<int>& nums) {int sum = 0;// dp[i]中的i表示背包内总和// 题目中说:每个数组中的元素不会超过 100,数组的大小不会超过 200// 总和不会大于20000,背包最大只需要其中一半,所以10001大小就可以了vector<int> dp(10001, 0);for (int i = 0; i < nums.size(); i++) {sum += nums[i];}// 也可以使用库函数一步求和// int sum = accumulate(nums.begin(), nums.end(), 0);if (sum % 2 == 1) return false;int target = sum / 2;// 开始 01背包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]);}}// 集合中的元素正好可以凑成总和targetif (dp[target] == target) return true;return false;}
};

 

今日总结

01背包是后续背包问题的基础

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

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

相关文章

【C++】组合数

题目描述 组合数表示的是从n个物品中选出m个物品的方案数。举个例子&#xff0c;从 (1, 2, 3) 三个物品中选择两个物品可以有 (1, 2)&#xff0c;(1, 3)&#xff0c;(2, 3) 这三种选择方法。 根据组合数的定义&#xff0c;我们可以给出计算组合数的一般公式&#xff1a; 其中…

C++ 日期计算器

日期计算器 概要 Date类的规划Date类的实现Date 构造函数Date 拷贝构造函数~Date 析构函数GetMonthDay 求某年某月的天数operator 赋值操作符重载operator 加等操作符重载operator 加号操作符重载operator- 减等操作符重载operator- 减法操作符重载 &#xff08;日期 - 天数&am…

2023年第四季度硬盘容量强势增长9%

在2023年第四季度&#xff08;CQ4 23&#xff09;&#xff0c;硬盘驱动器&#xff08;HDD&#xff09;市场的总容量出货量环比增长9%&#xff0c;达到214EB&#xff0c;而单位出货量保持在2900万块不变。其中&#xff0c;近线存储&#xff08;Nearline&#xff09;硬盘的容量出…

Java基于微信小程序的驾校报名小程序,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

JVM双亲委派机制

双亲委派模型是一种组织类加载器之间关系的一种规范,他的工作原理是:如果一个类加载器收到了类加载的请求,它不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,这样层层递进,最终所有的加载请求都被传到最顶层的启动类加载器中,只有当父类加载器无法完成这个加载…

基于SSM的实习管理系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的实习管理系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring Spri…

Verilog刷题笔记19

题目&#xff1a; A common source of errors: How to avoid making latches When designing circuits, you must think first in terms of circuits: I want this logic gate I want a combinational blob of logic that has these inputs and produces these outputs I want…

【高阶数据结构】B-树详解

文章目录 1. 常见的搜索结构2. 问题提出使用平衡二叉树搜索树的缺陷使用哈希表的缺陷 3. B-树的概念4. B-树的插入分析插入过程分析插入过程总结 5. B-树的代码实现5.1 B-树的结点设计5.2 B-树的查找5.3 B-树的插入实现InsertKey插入和分裂测试 6. B-树的删除&#xff08;思想&…

使用WPS制作三线表

点击边框和底纹点击1、2、3、4并且应用于表格点击确定 再次选中表格点击右键表格属性选择边框和底纹 选中表格第一行右键点击表格属性选择边框和底纹 如果表格中存在虚线

【Linux开发工具】gcc/g++的使用

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 1.前言2.gcc/g使用方…

【自动化测试】---Selenium+Java

1.自动化测试分类 接口自动化测试UI自动化测试&#xff08;移动端自动化测试、Web端自动化测试&#xff09; 2.选择Selenium作为web自动化工具原因&#xff08;面试题&#xff09; 开源免费支持多个浏览器支持多个系统支持多语言Selenium包提供很多供测试使用的API 3.自动化是什…

C++内存模型的内存布局

C内存模型的内存布局 什么是内存模型内存布局及作用C程序的内存布局 本文章介绍了C程序的内存布局&#xff0c;并附有一段演示 数据区和 栈区存储不同类型变量的代码示例。 什么是内存模型 在计算机科学中&#xff0c;程序的内存模型是指程序在内存中的组织结构和存储方式的抽…

编译原理实验2——自上而下语法分析LL1(包含去消除左递归、消除回溯)

文章目录 实验目的实现流程代码运行结果测试1&#xff08;含公共因子&#xff09;测试2&#xff08;经典的ii*i文法&#xff0c;且含左递归&#xff09;测试3&#xff08;识别部分标识符&#xff09; 总结 实验目的 实现自上而下分析的LL1语法分析器&#xff0c;给出分析过程 …

[C#] 如何使用ScottPlot.WPF在WPF桌面程序中绘制图表

什么是ScottPlot.WPF&#xff1f; ScottPlot.WPF 是一个开源的数据可视化库&#xff0c;用于在 WPF 应用程序中创建高品质的绘图和图表。它是基于 ScottPlot 库的 WPF 版本&#xff0c;提供了简单易用的 API&#xff0c;使开发人员能够通过简单的代码创建各种类型的图表&#…

2、6作业

TCP和UDP的区别 TCP和UDP都是通信协议 TCP提供有连接的&#xff0c;稳定的&#xff0c;无误码无失真无乱序无丢失的通信 UDP提供无连接的&#xff0c;尽力的&#xff0c;可能误码可能乱序&#xff0c;可能丢失的通信 TCP每发一个数据包就需要对方回应一个应答包&#xff0c…

自定义npm包从vue2升级到vue3遇到的问题解决

1.执行npm run build时报错&#xff1a; (node:16724) UnhandledPromiseRejectionWarning: SyntaxError: Unexpected token ‘??’ at Loader.moduleStrategy (internal/modules/esm/translators.js:149:18 解决&#xff1a;更新node版本 查看了我使用的node版本是14.21.3&…

《合成孔径雷达成像算法与实现》Figure6.10

clc clear close all参数设置 距离向参数设置 R_eta_c 20e3; % 景中心斜距 Tr 2.5e-6; % 发射脉冲时宽 Kr 20e12; % 距离向调频率 alpha_os_r 1.2; % 距离过采样率 Nrg 320; % 距离线采样数 距离向…

UUID和雪花(Snowflake)算法该如何选择?

UUID和雪花(Snowflake)算法该如何选择&#xff1f; UUID 和 Snowflake 都可以生成唯一标识&#xff0c;在分布式系统中可以说是必备利器&#xff0c;那么我们该如何对不同的场景进行不同算法的选择呢&#xff0c;UUID 简单无序十分适合生成 requestID&#xff0c; Snowflake 里…

Flink实战六_直播礼物统计

接上文&#xff1a;Flink实战五_状态机制 1、需求背景 现在网络直播平台非常火爆&#xff0c;在斗鱼这样的网络直播间&#xff0c;经常可以看到这样的总榜排名&#xff0c;体现了主播的人气值。 人气值计算规则&#xff1a;用户发送1条弹幕互动&#xff0c;赠送1个荧光棒免费…

07-使用Package、Crates、Modules管理项目

上一篇&#xff1a;06-枚举和模式匹配 当你编写大型程序时&#xff0c;组织代码将变得越来越重要。通过对相关功能进行分组并将具有不同功能的代码分开&#xff0c;您可以明确在哪里可以找到实现特定功能的代码&#xff0c;以及在哪里可以改变功能的工作方式。 到目前为止&…