动态规划:01背包理论基础 一维dp数组(滚动数组)

news2024/11/30 0:41:51
  1. 确定dp数组的定义

    在一维dp数组中,dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j]。

  2. 一维dp数组的递推公式

    dp[j]为 容量为j的背包所背的最大价值,那么如何推导dp[j]呢?

    dp[j]可以通过dp[j - weight[i]]推导出来,dp[j - weight[i]]表示容量为j - weight[i]的背包所背的最大价值。

    dp[j - weight[i]] + value[i] 表示 容量为 j - 物品i重量 的背包 加上 物品i的价值。(也就是容量为j的背包,放入物品i了之后的价值即:dp[j])

    此时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]);

可以看出相对于二维dp数组的写法,就是把dp[i][j]中i的维度去掉了。

  1. 一维dp数组如何初始化

    p[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j],那么dp[0]就应该是0,因为背包容量为0所背的物品的最大价值就是0。

    那么dp数组除了下标0的位置,初始为0,其他下标应该初始化多少呢?

    递归公式:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

    dp数组在推导的时候一定是取价值最大的数,如果题目给的价值都是正整数那么非0下标都初始化为0就可以了。

    这样才能让dp数组在递归公式的过程中取的最大的价值,而不是被初始值覆盖了。

    那么假设物品价值都是大于0的,所以dp数组初始化的时候,都初始为0就可以了。

  2. 一维dp数组遍历顺序

代码如下:

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]);

    }
}

这里和二维dp的写法中,遍历背包的顺序是不一样的!二维dp遍历的时候,背包容量是从小到大,而一维dp遍历的时候,背包是从大到小。

倒序遍历是为了保证物品i只被放入一次!。但如果一旦正序遍历了,那么物品0就会被重复加入多次!

举例: 物品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

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

那么问题又来了,为什么二维dp数组历的时候不用倒序呢?

因为对于二维dp,dp[i][j]都是通过上一层即dp[i - 1][j]计算而来,本层的dp[i][j]并不会被覆盖!

代码中是先遍历物品嵌套遍历背包容量,顺序不能颠倒!!!

  1. 推导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();
}

学习自:代码随想录。

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

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

相关文章

Ubuntu20.04解决疑难杂症问题问题合集

下列问题都是我一次性遇见的倒霉不。 问题一&#xff1a; 安装 linux 版网络调试助手&#xff0c;安装成功后打不开运行文件 解决办法&#xff1a; #通过执行可执行文件打开 # 进入到可执行文件下 cd /opt/mNetAssist/ # 运行主程序 ./mNetAssis 如果出现&#xff1a; libq…

体检中心智能导检系统排队是什么流程?

随着智能信息化建设的推进下&#xff0c;体检中心也越来越规范化、现代化、智能化&#xff0c;智能导检系统&#xff0c;有效完善体检中心服务水平&#xff0c;简化体检流程&#xff0c;节省排队等候时间&#xff0c;提高体检的效率&#xff0c;也能提升体检服务中心的形象。 下…

JVM 执行引擎

执行引擎概述 是Java 虚拟机核心的组成部分之一物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统层面上的&#xff0c;而虚拟机的执行引擎则是由软件自行实现的&#xff0c;因此可以不受物理条件制约地定制指令集与执行引擎的结构体系&#xff0c;能够执行哪些不被…

2、Flume进阶

目录 1、Flume事务 1.1 Flume事务 1.2 Flume Agent内部原理 1.3 重要组件&#xff1a; 2、 Flume拓扑结构 2.1 简单串联 2.2 复制和多路复用 2.3 负载均衡和故障转移 2.4 聚合 3、开发案例 3.1 复制和多路复用 3.4.2 负载均衡和故障转移 3.3 聚合 1、Flume事务 1.…

在数据化知识经济的时代,你该学会如何经营好自己的知识管理

在当今的数据化知识经济时代&#xff0c;知识管理已经越来越成为了一个必备的技能。在这个竞争激烈的时代&#xff0c;拥有良好的知识管理能力&#xff0c;可以帮助我们更好地应对各种挑战和机遇。 如何经营好自己的知识管理 一、认识知识管理的重要性 知识管理是指通过系统…

【计算机视觉】如何利用 CLIP 做简单的图像分类任务?(含源代码)

要使用 CLIP 模型进行预测&#xff0c;您可以按照以下步骤进行操作&#xff1a; 一、安装 安装依赖&#xff1a;首先&#xff0c;您需要安装相应的依赖项。您可以使用 Python 包管理器&#xff08;如 pip &#xff09;安装 OpenAI 的 CLIP 库。 pip install githttps://gith…

2023年Android开发者路线-第1部分

2023年Android开发者路线-第1部分 2023年Android开发者路线-第2部分 2023年Android开发者路线-第3部分 2023年Android开发者路线-第4部分 2023年Android开发者路线-第1部分 Android 生态系统处于不断发展的状态&#xff1a;每天都会引入新的库和资料&#xff0c;旨在加快开…

linux常见指令以及权限理解

1.linux下基本指令&#xff1a; ls指令&#xff1a; 查看文件的属性 ls-l&#xff1a;文件的属性 ls-la:显示所有文件的属性 ls *&#xff1a; linux任何一个目录下面都有两个隐藏文件&#xff1a; ..&#xff1a;表示当前路径的上级路径&#xff0c;可以原路返回 .&…

分布式锁-01(单节点解决方案)

分布式锁概述 为什么需要分布式锁 在单机部署的系统中&#xff0c;使用线程锁来解决高并发的问题&#xff0c;多线程访问共享变量的问题达到数据一致性&#xff0c;如使用synchornized、 ReentrantLock等。 但是在后端集群部署的系统中&#xff0c;程序在不同的JVM虚拟机中运行…

可调整界面输出的桌面万年历设计

可调整界面输出的桌面万年历设计 本文主要介绍月历和生辰八字五行的界面输出方法。一个有趣的方法是可调整界面输出格式&#xff0c;显示几种屏幕排版的布局。本文示例了四个式样。算法的精髓是用一种简单的算法来设置调节屏幕打印输出。分三个显示内容&#xff0c;即月历、大字…

Docker入门实战---修改Docker镜像源

前言 现在大部分互联网公司在实施项目时几乎都会以微服务架构进行落地&#xff0c;那么微服务一旦多了之后就会面临一个如何友好的治理的问题&#xff0c;本人不会重点介绍治理的问题&#xff0c;而是会简单就治理的其中一个环节服务部署运维的问题进行介绍&#xff0c;服务部…

排序算法之桶排序

一、桶排序&#xff08;BucketSort&#xff09; 桶排序&#xff08;Bucket sort&#xff09;或所谓的箱排序&#xff0c;是一个排序算法&#xff0c;工作的原理是将数组分到有限数量的桶里。每个桶再个别排序&#xff08;有可能再使用别的排序算法或是以递归方式继续使用桶排序…

[论文阅读] (28)李沐老师视频学习——1.研究的艺术·跟读者建立联系

《娜璋带你读论文》系列主要是督促自己阅读优秀论文及听取学术讲座&#xff0c;并分享给大家&#xff0c;希望您喜欢。由于作者的英文水平和学术能力不高&#xff0c;需要不断提升&#xff0c;所以还请大家批评指正&#xff0c;非常欢迎大家给我留言评论&#xff0c;学术路上期…

如何成功申请计算机软件著作权【流程完整记录】

致谢 &#xff1a;此博文的编写包括软著的申请&#xff0c;均借鉴了大佬【万里守约】的博客https://blog.csdn.net/qq_45625499/article/details/123463407 提示&#xff1a;此博文仅适合个人申请&#xff0c;因为我是自己一个人的项目&#xff0c;自己一个人申请软著 文章目录…

2023 Android开发者路线-第一部分

2023 Android开发者路线-第一部分 Android 生态系统处于不断发展的状态&#xff1a;每天都会引入新的库和资料&#xff0c;旨在加快开发速度并让我们作为开发人员的生活更轻松。 在这个由多个部分组成的系列中&#xff0c;您将按照我们的2023 年 Android 开发者路线图了解有关…

pyhton GUI编程之Tkinter美化皮肤ttkbootstrap

文章目录 pyhton GUI编程之Tkinter美化皮肤ttkbootstrap介绍 pyhton GUI编程之Tkinter美化皮肤ttkbootstrap介绍 tkinter 相对简单&#xff0c;学习入门很快&#xff0c;但是做出来的GUI界面不够美观&#xff0c;各个组件的外观都很老土&#xff0c;所谓 " 爱美之心&#…

发现一个国产BI软件,做财务数据分析效果绝了

如果是一般的财务数据分析&#xff0c;BI软件们都能做&#xff0c;但如果真要深入了解财务痛点&#xff0c;逐个击破财务数据分析难点&#xff0c;实现多维立体自助式的财务数据分析&#xff0c;那就难。就目前而言&#xff0c;财务数据分析做得好的国产BI软件也就一个奥威BI软…

使用docker构建ElasticSearch集群

目录 一、准备工作 二、编写docker-compose.yml 三、编写ElasticSearch和kibana的配置文件 四、执行构建ElasticSearch集群 五、验证结果&#xff1a; 六、可视化工具 ElasticSearch可视化工具介绍&#xff08;elasticsearch-head、kibana、elasticHD&#xff09; 一、e…

CTF权威指南 笔记 -第四章Linux安全机制-4.1-Stack Canaries

目录 Stack Canaries 简介 我们进行简单的例子 64 32 checksec Stack Canaries 是对抗栈溢出攻击的技术 SSP安全机制 Canary 的值 栈上的一个随机数 在程序启动时 随机生成并且保存在比返回地址更低值 栈溢出是从低地址向高地址进行溢出 如果攻击者要攻击 就一定要覆…

电动力学专题:圆柱形导体中趋肤效应

电动力学分析 金属导体内的电流密度方程 由Maxwell方程组导出Helmhltz方程 对于良导体,有\sigma/(\omega \eprsilon),因此有 圆柱形导线中电流密度分布 设电流沿Z轴方向流动,均匀导体,可简化为 通解&#xff1a; 安培环路定理 定态电磁波的Maxwell方程组 贝塞尔函数性质&…