C++算法初级11——01背包问题(动态规划2)
C++算法初级11——01背包问题(动态规划2)
文章目录
- C++算法初级11——01背包问题(动态规划2)
- 问题引入
- 0-1背包问题分析
- 0-1背包问题的形式化分析
- 优化
问题引入
辰辰采药
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是辰辰,你能完成这个任务吗?
辰辰采药在算法中属于一种很经典的0-1背包问题。更一般的,这种问题可以转化为:
给定n个物品,每个物体有个体积v i和一个价值p i
现有一个容量为V的背包,请问如何选择物品装入背包,使得获得的总价值最大?
0-1背包问题分析
0-1背包问题描述:给定n个物品,每个物体有个体积v i和一个价值p i
现有一个容量为V的背包,请问如何选择物品装入背包,使得获得的总价值最大?
基本思路
考虑到现在我们能做的决策,只有对于每个物品的“选”与“不选”。所以,这个问题就是
- 以“将每一个物品依次放入背包”划分不同阶段
- 而对于每个物品的“选与不选”就是不同决策
考虑到所有的放置前i个物品的方案数可以分为两类:
- 一个是放第i个物品,
- 一个是不放第i个物品
所以下面我们分这两种情况来讨论。因为在决策的过程中,变化的是当前所在的阶段,以及容量的剩余大小。
所以,我们维护一个二维状态f[i,j], 来表示前i个物品,放到体积为j的背包里,可以得到的最大价值。
首先,考虑容量为任意值j时,将前i个物品放入背包的情况。
所以,状态转移方程为 f [ i ] [ j ] = m a x { f [ i − 1 , j ] , p [ i ] + f [ i − 1 ] [ j − v [ i ] } f[i][j]=max\{f[i-1,j],p[i]+f[i-1][j-v[i]\} f[i][j]=max{f[i−1,j],p[i]+f[i−1][j−v[i]}
0-1背包问题的形式化分析
使用动态规划解决问题,需要明确状态设计、转移方程、初始状态和转移方向四个方面。
那现在,让我们来明确一下该0-1背包问题中的动态规划四要素:
- 状态:
用f[i][j]表示前i个物品,放在空间为j的背包里,能获得的最大收益。 - 转移方程:
因为每一个阶段有至多两种选择,所以需要分别计算两种选择的收益后取较大值。
f[i][j] = f[i - 1][j] // j < v[i],表示装不下第i个物品
f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + p[i]); // otherwise
- 初始状态:
在一个物品都没放的时候,无论背包大小多少,总价值都是0,即
f[0][j] = 0 // 0 <= j <= V
- 转移方向:
观察转移方程,发现要想保证等式右边的状态一定比左边的状态先算出来,只需要保证i从小到大计算即可。
最终该问题的答案就是f[n,V]。这样,0-1背包问题就可以使用动态规划来解决~
代码
# include <bits/stdc++.h>
using namespace std;# define N 1002
int n=3;
int V = 70;
vector<int> v = {0,71,69,1};//体积
vector<int> p ={0,100,1,2};//价值
// 第0位,置为0,不参与计算,便于与后面的下标进行统一
int f[N][N];int main()
{for(int j=0;j<=V;j++)f[0][j]=0;for(int i=1;i<=n;i++){if(v[i]>V)continue;for(int j=0;j<=V;j++){if(j<v[i])f[i][j]=f[i-1][j];elsef[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+p[i]);}}cout<<f[n][V]<<endl;
}
动态规划的主要工作:就是算出不同状态下的结果,然后用相应维数的数组保存。
所以,整个动态规划的过程就是一个”填表“的过程。
优化
滚动数组优化
因为整个动态规划的过程就是一个填表的过程,如下图:
而在本题中,填表的顺序就是:填完上一行,然后填下一行。而且我们发现,下一行的状态,只会用到上一行的状态来转移。所以,当我们在计算第i行时,其实前i−2行的状态就都没必要保留了。所以,我们可以用一种类似于”踩石头过河“的思想。
试想如果我们有一些石头,想利用这些石头过河。
如果石头的数量很多,那么最方便的方法就是用这些石头铺一道石头路,这样我们就可以顺利过河。这就相当于我们可以开很充足的数组,然后把计算的每个阶段都存在数组里。
但如果我们只有两块石头,就过不了河了吗?不是的。我们可以用下图的方法一边走一边挪动石头,这样也可以顺利过河。
在空间优化的方法中,有一种很常见就是利用过河的思想。这种方法叫做滚动数组。在整个算法过程中,我们只用2×V的数组f[2][V]来记录状态。其中,所有奇数行的状态填入f[1][j]中,所有偶数行的状态填入f[0][j]中,如下图
# include <bits/stdc++.h>
using namespace std;# define N 1002
int n=3;
int V = 70;
vector<int> v = {0,71,69,1};//体积
vector<int> p ={0,100,1,2};//价值
// 第0位,置为0,不参与计算,便于与后面的下标进行统一
int f[2][N];//f[i][j]表示前i个物品,体积为j的最大价值int main()
{for(int i=1;i<=n;i++){for(int j=0;j<=V;j++){if(j<v[i])f[i&1][j] = f[(i-1)&1][j];elsef[i&1][j] = max(f[(i-1)&1][j],f[(i-1)&1][j-v[i]]+p[i]);}}cout<<f[n&1][V]<<endl;return 0;
}
算法优化2 —— 优化到一维数组
那么我们可不可以再进一步优化空间,使得只用一个一维数组就能解决整个问题了呢?
想到之前“踩石头过河”的类比,我们可能会觉得不太可能。但是如果我们进一步分析整个表的填写,如下图:
会发现下一行的某个状态,正好是由它上面的元素,以及左上方的某个元素转移而来。所以我们需要保证当计算黄色状态时上面两个绿色状态没有被覆盖掉。所以,当我们计算第i行时,完全可以将j从大到小枚举,这样在计算状态f(i,j)之前,数组f[j]中存储的是状态f[i−1,j],更新完以后,
f[j]中存的状态就是f[i,j]了。如下图:
# include <bits/stdc++.h>
using namespace std;# define N 1002
int n=3;
int V = 70;
vector<int> v = {0,71,69,1};//体积
vector<int> p ={0,100,1,2};//价值
// 第0位,置为0,不参与计算,便于与后面的下标进行统一
int f[N];int main()
{for(int i=1;i<=n;i++){for(int j=V;j>=v[i];j--){f[j] = max(f[j],f[j-v[i]]+p[i]);}}cout<<f[V]<<endl;return 0;
}
相关文章:

C++算法初级11——01背包问题(动态规划2)
C算法初级11——01背包问题(动态规划2) 文章目录 C算法初级11——01背包问题(动态规划2)问题引入0-1背包问题分析0-1背包问题的形式化分析优化 问题引入 辰辰采药 辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大…...

Python 库大全(下)
格式化输出 模块 reprlib 提供了一份定制的 repr(),用于简洁 地展示各种大的或者多层嵌套的容器变量: >>> import reprlib >>> reprlib.repr(set(\supercalifragilisticexpialidocious\)) "{\a\, \c\, \d\, \e\, \f\, \g\, ...…...

如何用链表实现LRU缓存淘汰算法
链表学习 一、 缓存1.1缓存介绍1.2 缓存策略 二、链表结构2.1 单链表2.2 循环链表2.3 双向链表2.4 双向循环链表2.5 链表与数组性能对比 三、如何基于链表实现LRU缓存淘汰算法 一、 缓存 1.1缓存介绍 缓存是一种提高数据读取性能的技术,在硬件设计、软件开发中都有…...

【01】数据结构与算法基础-数据、数据元素、数据项和数据对象 | 数据类型和抽象数据类型 | 抽象数据类型的表示和C++实现
目录) 0.数据结构的研究内容1.数据、数据元素、数据项和数据对象1.1数据1.2数据元素(Data element)和数据项1.3数据项1.4数据对象1.5数据结构(Data Structure)1.6逻辑结构的种类1.7存储结构的种类2.数据类型和抽象数据类型2.1数据类型(Data Type)2.2抽象数据类型(Abstract …...

PHP匿名类的使用场景有哪些?PHP匿名类怎么用?有什么好处?PHP匿名类如何在运行时动态生成?
以下是一些使用匿名类的场景: 2. 简单的工厂模式:当需要在运行时动态创建一些简单的对象时,可以使用匿名类替代创建不必要的类定义和文件。 function createGreeter($name) {return new class($name) {private $name;public function __cons…...

【并发基础】一篇文章带你彻底搞懂Java线程中断的底层原理——interrupt()、interrupted()、isInterrupted()
目录 〇、Java线程中断与阻塞的区别 0.1 线程中断 0.2 线程阻塞 一、线程的中断 二、中断方法 2.1 void interrupt() 2.1.1 可中断的阻塞 2.1.2 不可中断的阻塞 2.1.3 实践案例 2.2 boolean isInterrupted() 2.3 boolean interrupted() 2.4 代码案例 三、源码分析…...

【c语言】函数的数据传递原理 | 数组传入函数方法
创作不易,本篇文章如果帮助到了你,还请点赞支持一下♡>𖥦<)!! 主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步! 给大家跳段街舞感谢支持!ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…...

vue3源码(3)——computed
Vue3中的computed底层源码主要是通过使用Proxy对象来实现的。下面是对Vue3中computed底层源码的详细解读: 在Vue3中,computed的实现是通过使用createComputed函数来创建的。createComputed函数接收两个参数:getter和setter。 在createComput…...

数学建模第七天:数学建模算法篇之插值及MATLAB实现
目录 一、前言 1、引例 2、拟合定义 3、拟合与插值的关系 二、拟合 1、线性最小二乘法求解 ①思路 ②解法 2、MATLAB对线性最小二乘拟合的实现 ①函数说明 ②求解例题 3、MATLAB实现非线性曲线拟合 ①lsqcurvefit函数 ②代码求解 4、MATLAB实现非线性最小二乘拟…...

RUST 每日一省:生命周期作用域
生命周期 一个变量的生命周期就是它从创建到销毁的整个过程。 作用域 我们声明的每个变量都有作用域。作用域其实是变量和值存在的环境。作用域是由一对花括号表示的。例如,使用块表达式会创建一个作用域,即任何以花括号开头和结尾的表达式。此…...

【过程8】——能量守恒视角总结感受
一、背景 另一个角度的看到,观望着过程中自己曾经类似的经历(小舅子的工作)。 时间久了,经历多了,感悟会更加的充实;最近自己对于人在维持能量的过程中也有很多的感悟,一并做一下总结 二、过程 1.人为什么天性不愿意…...

kong(4):限流配置
Kong 提供了 Rate Limiting 插件,实现对请求的限流功能,避免过大的请求量过大,将后端服务打挂。 Rate Limiting 支持秒/分/小时/日/月/年多种时间维度的限流,并且可以组合使用。例如说:限制每秒最 多 100 次请求&…...

人脸识别 Face Recognition 入门
人脸识别 Face Recognition 入门概述 总述传统特征方法深度学习方法损失函数改进基于欧几里德和距离的损失基于角度/余弦边距的损失SoftMax 损失及其变体 一级标题二级标题二级标题二级标题 找论文搭配 Sci-Hub 食用更佳 💪 Sci-Hub 实时更新 : https://tool.yovisu…...

【AI绘画】Midjourney的使用及程序示例
Midjourney 1.背景2.Midjourney的原理3.Midjourney的使用方法4.Midjourney的示例代码 1.背景 Midjourney 是一款基于深度学习的图像转换工具,其可以将一张图像转换成具有不同风格的图像,例如将一张照片转换成卡通风格的图像。Midjourney 基于 TensorFlow…...

无公网IP?教你在外远程访问本地wamp服务器「内网穿透」
目录 前言 1.Wamp服务器搭建 1.1 Wamp下载和安装 1.2 Wamp网页测试 2. Cpolar内网穿透的安装和注册 2.1 本地网页发布 2.2 Cpolar云端设置 2.3 Cpolar本地设置 3. 公网访问测试 4. 结语 前言 软件技术的发展日新月异,各种能方便我们生活、工作和娱乐的新…...

leetcode 628. 三个数的最大乘积
题目描述解题思路执行结果 leetcode 628. 三个数的最大乘积 题目描述 三个数的最大乘积 给你一个整型数组 nums ,在数组中找出由三个数组成的最大乘积,并输出这个乘积。 示例 1: 输入:nums [1,2,3] 输出:6 示例 2&…...

fork函数如何创建进程,exit/_exit函数如何使进程终止的详细分析与代码实现
🎊【进程通信与并发】专题正在持续更新中,进程,线程,IPC,线程池等的创建原理与运用✨,欢迎大家前往订阅本专题,获取更多详细信息哦🎏🎏🎏 🪔本系列…...

重置电脑时提示“缺少所需的驱动器分区”怎么办?
当您启动Windows 10电脑并收到“您的电脑/设备需修复”这个消息提示时,您会马上尝试修复电脑,如果您这样做了,您可能会收到一个“安装Windows的驱动器已被锁定”的信息。如果您尝试重置您的电脑,您可能会收到一条提示,…...

在KylinV10安装Dm8
前言 因为近期,业外和几个朋友想搞点有趣的项目玩玩,既然不以盈利为主,就> 主推国产化,所以这篇记录一下,我在KylinV10安装dm8.最近真的很忙,要负责专研一下国产化工具开发的事,还要负责tb级…...

「SQL面试题库」 No_46 交换工资
🍅 1、专栏介绍 「SQL面试题库」是由 不是西红柿 发起,全员免费参与的SQL学习活动。我每天发布1道SQL面试真题,从简单到困难,涵盖所有SQL知识点,我敢保证只要做完这100道题,不仅能轻松搞定面试࿰…...

SLAM论文速递【SLAM—— RDS-SLAM:基于语义分割方法的实时动态SLAM—4.24(1)
论文信息 题目: RDS-SLAM:Real-Time Dynamic SLAM Using Semantic Segmentation Methods RDS-SLAM:基于语义分割方法的实时动态SLAM论文地址: https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber9318990发表期刊: IEEE Access ( Volum…...

OJ练习第82题——填充书架
填充书架 力扣链接:1105. 填充书架 题目描述 给定一个数组 books ,其中 books[i] [thicknessi, heighti] 表示第 i 本书的厚度和高度。你也会得到一个整数 shelfWidth 。 按顺序 将这些书摆放到总宽度为 shelfWidth 的书架上。 先选几本书放在书架…...

OHOS IDE和SDK的安装方法
参照OpenHarmony应用开发环境安装流程,下载安装OHOS的IDE,过程中需要全程联网。 IDE,安装至D:\Tools\Huawei\DevEcoStudio。 IDE安装成功之后,按照提示下载安装HOS和OHOS的SDK。 nodejs,安装至D:\Tools\Huawei\nodejs…...

New Year Garland(计数类DP)
New Year Garland 题意 用m种颜色的球装饰n层的圣诞树,圣诞树的第i层由 l i l_{i} li个彩球串成,且同一层相邻的球颜色不同,相邻的层之间彩球颜色的集合不同,问有多少种方案,对p取模。 分析 首先先计算每一…...

32岁阿里P7,把简历改成不知名小公司,学历改成普通本科,工作内容不变,投简历全挂!...
hr靠什么来招人? 一位猎头讲述了自己和朋友打赌的故事: 朋友在阿里云,32岁,P7,他把简历上的公司改成不知名,学历改成普通本科,工作内容不变,结果投其他公司(比如京东&…...

从三室心脏MRI影像检测主动脉瓣病变
Detecting Aortic Valve Pathology from the 3-Chamber Cine Cardiac MRI View 摘要 背景 心脏磁共振(CMR)是量化心脏容量、功能和血流量的金标准。定制的MR脉冲序列定义了对比机制,采集几何形状和定时,可以在CMR期间应用,以实现独特的组织…...

【JavaWeb】JavaScript
1、JavaScript 介绍 Javascript 语言诞生主要是完成页面的数据验证。因此它运行在客户端,需要运行浏览器来解析执行 JavaScript 代码。 JS 是 Netscape 网景公司的产品,最早取名为 LiveScript;为了吸引更多 java 程序员。更名为 JavaScript。 JS 是弱…...

Apache Doris 1.2.4 Release 版本正式发布|版本通告
亲爱的社区小伙伴们,我们很高兴地宣布,Apache Doris 于 2023 年 4 月 27 日迎来 1.2.4 Release 版本的正式发布!在 1.2.4 版本中,Doris 团队已经修复了自 1.2.3 版本发布以来近 150 个问题或性能改进项。同时,1.2.4 版…...

【C++STL】map
文章目录 一. map的介绍二. map的使用结束语 一. map的介绍 map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素在map中,键值key通常用于排序和唯一地标识元素,而value中存储与此键值…...

vue2项目PC端如何适配不同分辨率屏幕
项目构建:基于vue-cli3构建,使用postcss-px2rem px2rem-loader进行rem适配 实现原理:每次打包,webpack通过使用插件postcss-px2rem,帮我们自动将px单位转换成rem单位前方有坑:UI框架部分组件使用JavaScript…...