当前位置: 首页 > news >正文

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[i1,j],p[i]+f[i1][jv[i]}

0-1背包问题的形式化分析

使用动态规划解决问题,需要明确状态设计、转移方程、初始状态和转移方向四个方面。

那现在,让我们来明确一下该0-1背包问题中的动态规划四要素:

  1. 状态:
    用f[i][j]表示前i个物品,放在空间为j的背包里,能获得的最大收益。
  2. 转移方程:
    因为每一个阶段有至多两种选择,所以需要分别计算两种选择的收益后取较大值。
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
  1. 初始状态:
    在一个物品都没放的时候,无论背包大小多少,总价值都是0,即
f[0][j] = 0 // 0 <= j <= V
  1. 转移方向:
    观察转移方程,发现要想保证等式右边的状态一定比左边的状态先算出来,只需要保证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背包问题&#xff08;动态规划2&#xff09; 文章目录 C算法初级11——01背包问题&#xff08;动态规划2&#xff09;问题引入0-1背包问题分析0-1背包问题的形式化分析优化 问题引入 辰辰采药 辰辰是个天资聪颖的孩子&#xff0c;他的梦想是成为世界上最伟大…...

Python 库大全(下)

格式化输出 模块 reprlib 提供了一份定制的 repr()&#xff0c;用于简洁 地展示各种大的或者多层嵌套的容器变量&#xff1a; >>> 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缓存介绍 缓存是一种提高数据读取性能的技术&#xff0c;在硬件设计、软件开发中都有…...

【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匿名类如何在运行时动态生成?

以下是一些使用匿名类的场景&#xff1a; 2. 简单的工厂模式&#xff1a;当需要在运行时动态创建一些简单的对象时&#xff0c;可以使用匿名类替代创建不必要的类定义和文件。 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语言】函数的数据传递原理 | 数组传入函数方法

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…...

vue3源码(3)——computed

Vue3中的computed底层源码主要是通过使用Proxy对象来实现的。下面是对Vue3中computed底层源码的详细解读&#xff1a; 在Vue3中&#xff0c;computed的实现是通过使用createComputed函数来创建的。createComputed函数接收两个参数&#xff1a;getter和setter。 在createComput…...

数学建模第七天:数学建模算法篇之插值及MATLAB实现

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

RUST 每日一省:生命周期作用域

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

【过程8】——能量守恒视角总结感受

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

kong(4):限流配置

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

人脸识别 Face Recognition 入门

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

【AI绘画】Midjourney的使用及程序示例

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

无公网IP?教你在外远程访问本地wamp服务器「内网穿透」

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

leetcode 628. 三个数的最大乘积

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

fork函数如何创建进程,exit/_exit函数如何使进程终止的详细分析与代码实现

&#x1f38a;【进程通信与并发】专题正在持续更新中&#xff0c;进程&#xff0c;线程&#xff0c;IPC&#xff0c;线程池等的创建原理与运用✨&#xff0c;欢迎大家前往订阅本专题&#xff0c;获取更多详细信息哦&#x1f38f;&#x1f38f;&#x1f38f; &#x1fa94;本系列…...

重置电脑时提示“缺少所需的驱动器分区”怎么办?

当您启动Windows 10电脑并收到“您的电脑/设备需修复”这个消息提示时&#xff0c;您会马上尝试修复电脑&#xff0c;如果您这样做了&#xff0c;您可能会收到一个“安装Windows的驱动器已被锁定”的信息。如果您尝试重置您的电脑&#xff0c;您可能会收到一条提示&#xff0c;…...

在KylinV10安装Dm8

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

「SQL面试题库」 No_46 交换工资

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

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...