【C++图文并茂】01背包问题不会?超详细的详解,看完保证你会
大家好,今天 给大家讲解01背包问题
有N件物品和一个容量为V的背包。第i件物品的体积是c[i],价值是w[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
01背包问题是典型的动态规划问题,我们拿葡萄矿泉水和西瓜举例子
这道题确实可以用暴力来做,但凡这给的数是10的七次方你咋办?
今天就教你们可以轻松拿捏这道题的方法:DP(动态规划)
要想要解出来这道题,咱们得先列一个表格
然后咱们的每个表格都要填写该表格所在列的背包容量最多可以在所在行的物品及以上所获得的价值总和最多能有多少
你是不是听蒙圈了?
那你就蒙圈吧 没有关系,下面我给你放一张图你就明白了
看懂了吧,这回还没看懂我真没办法了私信我吧
首先来看第零行
肯定都是零嘛,第零行是空气价值为0,无论如何肯定总价值是0
接下来看第零列,很明显,由于背包大小为0,装不了任何东西,所以都填0.
我们最终要求的答案在第六列第三航。
接着问题来了,第一列第一行的单元格怎么填?
很简单,葡萄的重量是2,背包大小只有1,连葡萄的大小都不够,所以填0
接下来看第一行,葡萄的重量是2,从第二列开始所有背包的重量都≥2,葡萄的价值为3,所以第一行的第2-6列均为3.
接下来看第二行,很明显,第二行的第1、2个背包的重量不够矿泉水的重量(3),所以它们的最优解全部继承于上方的单元格
接下来填写第二行第三列的单元格,该列的背包容量为3,葡萄和矿泉水都可以被其装进去,那么我们该比较了:
装完葡萄之后就不可以再装其他物品了,装葡萄的最优解为葡萄的价值,3.
装矿泉水之后,也不能装其他东西了,所以装矿泉水的最优解为矿泉水的价值,5.
5>3,所以这里应该填写5.
二行四列可以只装葡萄或只装矿泉水或只装西瓜(西瓜在第三行才会考虑,所以这里不考虑西瓜的情况)(因为这是01背包问题,01的意思是一个物品装的数量只有0和1,所以装两个葡萄是不可能的)所以也填5.
接着看二行的第五列,这一列背包容量达到了5,可以同时容纳葡萄和矿泉水, 所以这一格填8.
第六格同样填8.
接下来看第三行,这一行会考虑西瓜,第1-3列由于不够装西瓜,所以直接继承第二行的结果
第四列装完西瓜后没地方放别的东西了,所以价值是6,6>5,所以填6
第五列装完西瓜同样不能放别的东西,6<8,所以填写8.
最后,三行六列便是我们最终的答案。
这一格放西瓜后还有6-4=2的位置,正好放一个葡萄。这种方案的总价值是6+3=9,9比8大。
所以这一格填写9。
最后的答案便是9了。
而我们刚刚的表格再编程中可以用一个二维数组dp来表示。
总结一下思路:
-
状态定义:设
dp[i][j]
表示前i
件物品恰放入一个容量为j
的背包可以获得的最大价值。 -
状态转移方程:
- 不选第
i
件物品:dp[i][j] = dp[i-1][j]
- 选择第
i
件物品(前提是j >= w[i]
):dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i])
- 不选第
-
初始化:
dp[...]=0
,即没有物品时,价值都为0。
-
目标:
dp[n][W],也就是表格的最后一行最后一列
然后上模板代码
#include <iostream>
#include <vector>
using namespace std;int main() {int n, W; // n是物品个数,W是背包容量cin >> n >> W;vector<int> w(n + 1), v(n + 1); // w是重量数组,v是价值数组for (int i = 1; i <= n; i++) {cin >> w[i] >> v[i];}vector<vector<int>> dp(n + 1, vector<int>(W + 1, 0));// 动态规划填表for (int i = 1; i <= n; i++) {for (int j = 0; j <= W; j++) {if (j >= w[i]) {dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]);} else {dp[i][j] = dp[i - 1][j];}}}cout << dp[n][W] << endl; // 输出最大价值return 0;
}
但是这个代码有一个地方还可以优化,空间上,可以只用一维数组dp[j]
来存储上一行的结果,这样可以将空间复杂度从O(nW)降低到O(W)。
vector<int> dp(W + 1, 0);
for (int i = 1; i <= n; i++) {for (int j = W; j >= w[i]; j--) {dp[j] = max(dp[j], dp[j - w[i]] + v[i]);}
}
cout << dp[W] << endl;
注意一下,第二种写法中一维数组的实现中,内层循环需要倒序进行,以确保每次计算使用的是上一轮的结果。
好了,这一篇博客就写到这里,求点赞收藏关注 ,你们的支持就是我更新的最大动力!
相关文章:

【C++图文并茂】01背包问题不会?超详细的详解,看完保证你会
大家好,今天 给大家讲解01背包问题 有N件物品和一个容量为V的背包。第i件物品的体积是c[i],价值是w[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。 01背包问题是典型的动态规划问题,我们拿葡萄矿泉水和西…...
SQL自学:什么是子查询,如何使用它们
在 SQL(Structured Query Language,结构化查询语言)的世界里,子查询是一种强大的工具,它允许我们在一个 SQL 查询内部嵌套另一个查询。子查询也被称为内部查询或嵌套查询,为我们提供了一种灵活且强大的方式…...

No.10 笔记 | PHP学习指南:PHP数组掌握
本指南为PHP开发者提供了一个全面而简洁的数组学习路径。从数组的基本概念到高级操作技巧,我们深入浅出地解析了PHP数组的方方面面。无论您是初学者还是寻求提升的中级开发者,这份指南都能帮助您更好地理解和运用PHP数组,提高编码效率和代码质…...
RS-232 串口通信和 RS-485 串口通信的区别
RS-232 串口通信和 RS-485 串口通信有以下区别: 1. 通信方式: RS-232:全双工通信方式,即数据的发送和接收可以同时进行。在全双工模式下,通信双方可以在同一时刻既发送数据又接收数据,就像两个人可以同时…...
【K8s】专题十四(1):Kubernetes 安全机制之 RBAC
本文内容均来自个人笔记并重新梳理,如有错误欢迎指正! 如果对您有帮助,烦请点赞、关注、转发、订阅专栏! 专栏订阅入口 | 精选文章 | Kubernetes | Docker | Linux | 羊毛资源 | 工具推荐 | 往期精彩文章 【Docker】(全网首发)Kylin V10 下 MySQL 容器内存占用异常的解决…...

8. 多态、匿名内部类、权限修饰符、Object类
文章目录 一、多态 -- 花木兰替父从军1. 情境2. 小结 二、匿名内部类三、权限修饰符四、Object -- 所有类的父类(包括我们自己定义的类)五、内容出处 一、多态 – 花木兰替父从军 1. 情境 我们现在新建两个类HuaMuLan和HuaHu。HuMuLan是HuaHu的女儿,所以她会有她父…...
CentOS/Ubuntu/Debian安装LibeventCentOS安装Libevent库(含示例代码)库(含示例代码)
使用命令:CentOS安装Libevent库(含示例代码) sudo yum install libevent-devel Ubuntu/Debian: sudo apt install libevent-dev 示例代码: #include <stdio.h> #include <stdlib.h> #include <unistd.h> …...

【大数据】数据采集工具sqoop介绍
文章目录 什么是sqoop?一、Sqoop的起源与发展二、Sqoop的主要功能三、Sqoop的工作原理四、Sqoop的使用场景五、Sqoop的优势六、Sqoop的安装与配置 sqoop命令行一、Sqoop简介与架构二、Sqoop特点三、Sqoop常用命令及参数四、使用示例五、注意事项 什么是sqoop? Sqoop是一款开…...

vite学习教程02、vite+vue2配置环境变量
文章目录 前言1、安装依赖2、配置环境变量3、应用环境变量4、运行和构建项目资料获取 前言 博主介绍:✌目前全网粉丝3W,csdn博客专家、Java领域优质创作者,博客之星、阿里云平台优质作者、专注于Java后端技术领域。 涵盖技术内容࿱…...

k8s 的网络通信
目录 1 k8s通信整体架构 2 flannel 网络插件 2.1 flannel 插件组成 2.2 flannel 插件的通信过程 2.3 flannel 支持的后端模式 3 calico 网络插件 3.1 calico 简介 3.2 calico 网络架构 3.3 部署 calico 1 k8s通信整体架构 k8s通过CNI接口接入其他插件来实现网络通讯。目前比较…...
【编程基础知识】掌握Spring MVC:从入门到精通
摘要: 本文将深入探讨Spring MVC框架的核心概念、组件和工作流程。读者将学习如何将Spring MVC应用于现代Web应用程序开发中,并通过实际代码示例和流程图,理解其强大的功能和灵活性。文章最后,我们将通过一个Excel表格总结全文内容…...
多线程下,@Transactional失效解决
一、问题复现 批量插入时,使用多线程对插入数据实现分批插入,在service层使用Transactional注解,对应方法中线程池中开辟的子线程抛出异常时,没有回滚事务。 二、原因分析 事务管理范围不正确:Transactional注解仅对…...

PyCharm 项目解释器切换指南:如何在项目中更换 Python Interpreter
PyCharm 项目解释器切换指南:如何在项目中更换 Python Interpreter 文章目录 PyCharm 项目解释器切换指南:如何在项目中更换 Python Interpreter一 Settings 设置二 Project 选项三 Conda Environment四 更换 Environment 本文详细介绍了在 macOS 系统中…...

STM32F407寄存器操作(DMA+SPI)
1.前言 前面看B站中有些小伙伴吐槽F4的SPIDMA没有硬件可控的CS引脚,那么今天我就来攻破这个问题 我这边暂时没有SPI的从机芯片,并且接收的过程与发送的过程类似,所以这里我就以发送的过程为例了。 2.理论 手册上给出了如下的描述 我们关注…...
Oracle 的 OCP 与 MySQL 的 OCP 的区别
事务开始与提交(以 Java 代码中的事务操作为例) Oracle(在 Java 中使用 JDBC 进行事务操作) import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement;public cla…...

数据治理、数据清洗定义、区别以及数据清洗常用方法
一、数据治理定义 数据治理是一种组织数据管理的方法,涉及数据的收集、存储、处理、分析和共享等方面,旨在最大程度地利用数据资产并降低数据相关的风险。 数据治理确保数据的质量、安全性、合规性和可用性,以支持组织的决策和运营活动。…...

web基础-攻防世界
get-post 一、WP (题目本质:get与post传参方法) 用 GET 给后端传参的方法是:在?后跟变量名字,不同的变量之间用&隔开。例如,在 url 后添加/?a1 即可发送 get 请求。 利用 hackbar 进行…...

Java基础-String Class(字符串类)
String Java String 类概览 String 类是 Java 中最常用的类之一,用于处理字符串。以下是 String 类的主要特性和操作: 特性/操作描述不可变性String 对象一旦创建就不能被修改创建方式使用双引号 “” 或 String 构造函数字符串池Java 维护字符串常量池…...

《Linux服务与安全管理》| 服务进程与网络配置
《Linux服务与安全管理》| 服务进程与网络配置 目录 《Linux服务与安全管理》| 服务进程与网络配置 (1) 写出查看NetworkManager服务状态的命令。 (2) 写出查看NetworkManager服务自启动状态的命令。 (3࿰…...

No.15 笔记 | CSRF 跨站请求伪造
目录 一、基础知识 (一)cookie 和 session、同源策略 (二)CSRF 原理 二、CSRF 类型 (一)GET 类型 (二)POST 类型 三、CSRF 实例讲解 (一)真实案例 &am…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...

听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...

深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

Linux 下 DMA 内存映射浅析
序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存,但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程,可以参考这篇文章,我觉得写的非常…...

【51单片机】4. 模块化编程与LCD1602Debug
1. 什么是模块化编程 传统编程会将所有函数放在main.c中,如果使用的模块多,一个文件内会有很多代码,不利于组织和管理 模块化编程则是将各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数声明,其他.c文…...
GeoServer发布PostgreSQL图层后WFS查询无主键字段
在使用 GeoServer(版本 2.22.2) 发布 PostgreSQL(PostGIS)中的表为地图服务时,常常会遇到一个小问题: WFS 查询中,主键字段(如 id)莫名其妙地消失了! 即使你在…...