0/1背包
0/1背包
背包问题是DP最经典的类型之一,而0/1背包是最经典最基础的背包问题。
背包体积为 V V V, n n n种物品,每种物品只有1个,第 i i i种物品对应体积为 c i c_i ci,价值为 w i w_i wi,怎样装填能使背包总价值最大?
由于每件物品只有选(0)与不选(1)两种情况,故称为0/1背包问题。
分析:闫氏DP分析法

- 状态表示
- 集合:定义数组 d p [ i ] [ j ] dp[i][j] dp[i][j],表示当前选取方案的价值。第 i i i行表示只考虑前 i i i个物品的放置情况, j j j表示当前选取体积不超过 j j j的方案集合。
- 属性: M a x Max Max
- 初始化:对于最值问题, d p [ i ] [ 0 ] = f [ 0 ] [ j ] = 0 dp[i][0]=f[0][j]=0 dp[i][0]=f[0][j]=0
- 状态计算: d p [ i ] [ j ] dp[i][j] dp[i][j]:对于第 i i i种物品:
- 不可选第 i i i种物品: v < c [ i ] v<c[i] v<c[i],无法装入背包,背包剩余容积不变。集合状态仍为 [ 1 , i − 1 ] [1,i-1] [1,i−1],直接继承自第 i − 1 i-1 i−1种物品且背包容积仍为 j j j方案的价值。 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i−1][j]
- 可选第 i i i种物品:
- 不选第 i i i种物品:若选第 i i i种物品无法保证最优解,则不选,背包剩余容积不变。集合状态仍为 [ 1 , i − 1 ] [1,i-1] [1,i−1],直接继承自第 i − 1 i-1 i−1个物品且背包容积仍为 j j j方案的价值。 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i−1][j]
- 选第 i i i种物品:选第 i i i种物品可能导致产生最优解,则选。集合状态仍为 [ 1 , i − 1 ] [1,i-1] [1,i−1],因为0/1背包要求每种物品只能选一次,故继承自第 i − 1 i-1 i−1种物品且背包容积减少 c [ i ] c[i] c[i]方案的价值,并加 w [ i ] w[i] w[i]。 d p [ i ] [ j ] = d p [ i − 1 ] [ j − c [ i ] ] + w [ i ] dp[i][j]=dp[i-1][j-c[i]]+w[i] dp[i][j]=dp[i−1][j−c[i]]+w[i]
- 状态转移方程式: d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − c [ i ] ] + w [ i ] ) dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+w[i]) dp[i][j]=max(dp[i−1][j],dp[i−1][j−c[i]]+w[i])
遍历顺序:物品和背包谁先遍历都可以,根据状态转移方程式,dp数组的当前位置只与正上方和左上方有关,无论哪种遍历顺序,都可以确保在到达当前位置之前,正上方和左上方都有值。
初始化:

void init(){for(int i=0;i<=n;i++) dp[i][0]=0;for(int i=0;i<=v;i++) dp[0][j]=0;
}
void dp(){for(int i=1;i<=n;i++)//遍历物品for(int j=1;j<=v;j++)//遍历背包if(c[i]<=j) dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+w[i]);else dp[i][j]=dp[i-1][j];
}
时间复杂度O( n v nv nv),空间复杂度O( n v nv nv)
DP表

滚动数组
DP问题的空间复杂度一般很高,可采用滚动数组方式对空间复杂度进行优化。
滚动数组原理是基于DP的无后效性,第 i i i行只与 i − 1 i-1 i−1行有关,至于 i − 1 i-1 i−1行之前的数据第 i i i行无需关注,因此在DP过程中实际上只有两行在进行工作,故可极大程度优化空间复杂度。
注意,滚动数组使中间信息丢失,若需要输出背包具体方案,则不能采用滚动数组。
交替滚动
思路:定义 d p [ 2 ] [ v ] dp[2][v] dp[2][v],当前工作指针 w o r k work work和上次工作指针 o l d old old,使用 d p [ w o r k ] [ v ] dp[work][v] dp[work][v]和 d p [ o l d ] [ v ] dp[old][v] dp[old][v]进行交替滚动,每次滚动后交换工作指针即可,思路简单
int dp[2][v];
void dp(){int work=0,old=1;for(int i=1;i<=n;i++){swap(work,old);//交换工作指针而非交换数组元素for(int j=1;j<=v;j++)if(c[i]<=j) dp[work][j]=max(dp[old][j],dp[old][j-c[i]]+w[i]);else dp[work][j]=dp[old][j];}
}
自我滚动
思路:由状态转移方程式可知,当前元素只继承自上一行正上方( d p [ i − 1 ] [ j ] dp[i-1][j] dp[i−1][j])或上一行左上方( d p [ i − 1 ] [ j − 1 ] dp[i-1][j-1] dp[i−1][j−1]),因此逆序遍历背包容量进行更新,可将数组压至一维。
必须对背包进行逆序更新,这样是为了满足0/1背包每种物品只能选1个的性质,若顺序遍历则可能会对1种物品选多次,此时则为完全背包,且此错误必然会在选第1种物品时就发生。
自我滚动的0/1背包只可先遍历物品再遍历背包,不可颠倒(完全背包可颠倒)。
int dp[v];
void dp(){for(int i=1;i<=n;i++){//顺序遍历物品for(int j=v;j>=c[i];j--)//逆序遍历背包,装不下的不用管dp[j]=max(dp[j],dp[j-c[i]]+w[i]);}
}
输出具体方案
思路:定义标记数组,从 d p dp dp终点开始步步向上回溯,根据0/1背包状态转移方程式 p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − c [ i ] ] + w [ i ] ) p[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+w[i]) p[i][j]=max(dp[i−1][j],dp[i−1][j−c[i]]+w[i])可知,判断 d p [ i ] [ j ] dp[i][j] dp[i][j]与 d p [ i − 1 ] [ j ] dp[i-1][j] dp[i−1][j]和 d p [ i − 1 ] [ j − c [ i ] ] + w [ i ] dp[i-1][j-c[i]]+w[i] dp[i−1][j−c[i]]+w[i]关系即可判断第 i i i个物品是否已装,最后输出标记数组。
注:求解具体方案仅适用于非滚动数组,因为滚动过程会将中间状态信息丢失。
extern int dp[MAX][MAX],i,j;//i,j:dp终点
bool f[MAX];
void print(){for(;i>=1;i--){if(j>=c[i]&&dp[i][j]==dp[i-1][j-c[i]+w[i]]){//说明第i个物品已选f[i]=1;j-=c[i];}}for(int k=1;k<=n;k++) if(f[k]) cout<<k<<' ';
}
相关文章:

0/1背包
0/1背包 背包问题是DP最经典的类型之一,而0/1背包是最经典最基础的背包问题。 背包体积为 V V V, n n n种物品,每种物品只有1个,第 i i i种物品对应体积为 c i c_i ci,价值为 w i w_i wi,怎样装填能使…...
Linux的进程和权限的基本命令
目录 基本命令 man find date cal du ln exit grep 基本命令-帮助查询: wc cat more less head tail echo alias unalias 基本命令-进程管理: ps kill top 操作系统负载查看 用户分类: 程序用户 普通用户&#x…...

鼠标录制工具怎么挑选?9款电脑鼠标录制工具分享(2024)
你知道鼠标录制工具吗?鼠标录制工具通过记录和回放用户的操作,帮助自动化重复性任务,提高工作效率和精确性。它可以帮助用户简化很多繁琐的操作步骤,非常适合运用在电脑自动化任务、游戏自动化中,给大家整理了2024年9款…...

C1W4.LAB.Vector manipulation+Hash functions and multiplanes
理论课:C1W4.Machine Translation and Document Search 文章目录 Python 中的矢量操作Transforming vectorsExample 1Example 2 Frobenius Norm Hash functions and multiplanesBasic Hash tablesPlanesHash Function with multiple planesRandom PlanesDocument v…...

YOLOv8改进 | 检测头 | 融合渐进特征金字塔的检测头【AFPN4】
秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 专栏目录 :《YOLOv8改进有效…...

数据采集监控平台:挖掘数据价值 高效高速生产!
在当今数字化的时代,数据已成为企业非常宝贵的资产之一。然而,要充分发挥数据的潜力,离不开一个强大的数据采集监控平台,尤其是生产制造行业。它不仅是数据的收集者,更是洞察生产的智慧之眼,高效高速处理产…...

【算法笔记自学】第 9 章 提高篇(3)——数据结构专题(2)
9.1树与二叉树 #include <cstdio>int main() {int n, m;scanf("%d%d", &n, &m);printf(n m 1 ? "Yes" : "No");return 0; } 9.2二叉树的遍历 #include <cstdio> #include <vector> using namespace std;const int…...
Objective-C 中字符串的保存位置
在 Objective-C 中,字符串常量和动态创建的字符串(例如通过 stringWithFormat:、initWithString: 等方法创建的字符串)在内存中保存的位置一样么 ? 在 Objective-C 中,字符串常量和动态创建的字符串在内存中的保存位置…...
git 想要创建一个新的本地分支并检出远程分支的内容
如果你想要创建一个新的本地分支并检出远程分支的内容: git checkout -b feature-branch origin/feature-branch feature-branch 是你在本地创建的新分支名,origin/feature-branch 是远程分支的引用。 根据你检出的远程分支的名字而定 不知道名称的时…...

C语言学习笔记[24]:循环语句while②
getchar()的使用场景 int main() {char password[20] {0};printf("请输入密码:");//输入 123456 后回车scanf("%s", passwoed);//数组名本身就是数组地址printf("请确认密码:Y/N");int ch getchar();if(Y ch)printf(&…...
安全运营概述
安全运营概述 概述安全运营的工作对内安全运营工作对外安全运营工作品牌建设 概述 安全是一个过程,安全是靠运营出来的,公司会不断的有新业务的变更,新产品的发布,新版本的升级,技术架构的升级,底层系统的…...
spring-cloud和spring-cloud-alibaba的关系
首先Spring Cloud 是什么? Spring Cloud是一系列框架的有序集合,它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发。Spring Cloud提供了微服务架构开发所需的多种组件和工具,如服务发现注册、配置中心、消息总线、负载均…...

持续集成06--Jenkins构建触发器
前言 在持续集成(CI)的实践中,构建触发器是自动化流程中不可或缺的一环。它决定了何时启动构建过程,从而确保代码变更能够及时地得到验证和反馈。Jenkins,作为业界领先的CI/CD工具,提供了多种构建触发器选项…...

根据视图矩阵, 恢复相机的世界空间的位置
根据视图矩阵, 恢复相机的世界空间的位置 一、方法1 glsl 实现: // 从本地局部坐标系(相机空间) 到 世界空间的旋转变换 mat3 getLocal2WorldRotation() {mat3 world2localRotation mat3(viewMatrix[0].xyz,viewMatrix[1].xyz,viewMatrix[2].xyz);return inverse(world2loca…...
使用pytest-playwright截图和录制视频并添加到Allure报告
一、依赖环境 python, version==3.9.5 pytest-playwright, version==0.5.1 allure-pytest, version==2.13.5 pytest, version==6.2.5 allure, version==2.22.0pytest-playwright支持如下命令行参数: Playwright:--browser={chromium,firefox,webkit}Browser engine which …...
pytorch GPU cuda 使用 报错 整理
GPU 使用、报错整理 1. 使用指定GPU(单卡)1.1 方法1:os.environ[CUDA_VISIBLE_DEVICES]1.2 方法2:torch.device(cuda:2)1.3 报错1:RuntimeError: CUDA error: invalid device ordinal CUDA kernel errors might be asy…...
python + Pytest + requests 的接口自动化步骤
pythonpytestrequestallureyaml接口自动化测试项目实战 开发环境准备 1. jdk 下载 Java官网下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 安装: https://blog.csdn.net/VA_AV/article/details/138…...

基于若依的ruoyi-nbcio流程管理系统修正自定义业务表单的回写bug
更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio 演示地址:RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码: h…...

GD32 MCU上电跌落导致启动异常如何解决
大家是否碰到过MCU上电过程中存在电源波动或者电压跌落导致MCU启动异常的问题?本视频将会为大家讲解可能的原因以及解决方法: GD32 MCU上下电复位波形如下图所示,上电过程中如果存在吃电的模块,比如wifi模块/4G模块/开启某块电路…...

安防视频监控/视频汇聚EasyCVR平台浏览器http可以播放,https不能播放,如何解决?
安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台基于云边端一体化架构,兼容性强、支持多协议接入,包括国标GB/T 28181协议、部标JT808、GA/T 1400协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大华SDK、华为SDK、宇视SDK、乐橙SDK、萤石云SD…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...

抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...

【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...

claude3.7高阶玩法,生成系统架构图,国内直接使用
文章目录 零、前言一、操作指南操作指导 二、提示词模板三、实战图书管理系统通过4o模型生成系统描述通过claude3.7生成系统架构图svg代码转换成图片 在线考试系统通过4o模型生成系统描述通过claude3.7生成系统架构图svg代码转换成图片 四、感受 零、前言 现在很多AI大模型可以…...
CMake系统学习笔记
CMake系统学习笔记 基础操作 最基本的案例 // code #include <iostream>int main() {std::cout << "hello world " << std::endl;return 0; }// CMakeLists.txt cmake_minimum_required(VERSION 3.0)# 定义当前工程名称 project(demo)add_execu…...