背包九讲 之 01背包及二维背包

二维背包(包含优化) 二维背包 阅读详情

01背包问题

问题重述:

有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
第 i 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。

输出格式
输出一个整数,表示最大价值。

数据范围
0<N,V≤1000
0<vi,wi≤1000

解题思路:

经典的动态规划,我们需要找到一个合理的当前状态以及相应的状态转移方程。已知信息是物品数量N,背包总体积V,以及各个物品的价值。

找合适的状态

我们来尝试拆分出子问题,物品价值是物品的属性拆分它没有价值,那我们就来拆分N与V看看能不能分解出子问题,实际上是可以的,总问题是在物品数为N体积不超过V的情况下最大价值是多少。那我们就可以设想能否求出物品数为N-1体积不超过V-1的情况下最大价值是多少,这样我们就找到了我们的当前状态的表示方法,即用 f[ i ][ j ] 来表示前i个物品中在体积不超过j的情况下最大的价值是多少。

找状态转移方程

找到了当前状态的表示,我们便很容易理清边界情况,即当 i 或 j 为 0 时 f[ i ][ j ] 的值便为 0 ;接下来我们思考状态转移方程 f[ i ][ j +1] 能否通过 f[ i ][ j ] 得到呢?容量加一我们并不清楚之前的物品选择状态是什么,所以我们无法由 f[ i ][ j ] 得到 f[ i ][ j +1]。我们转换思路考虑 f[ i +1][ j ] 能否通过 f[ i ][ j ] 得到,我们发现是可以的,因为f[ i +1][ j ] 是比 f[ i ][ j ] 多一个可选物品的的状态。那么这个物品就有两种情况选与不选,如果我们不选这个物品那么f[ i +1][ j ] 的值就是 f[ i ][ j ] ,如果选了那么它的值就是选了这个物品的情况即f[ i ][ j -v[i]]+wi 那它是否可知呢,答案是肯定的,因为我们外层循环我们的i,内层就得循环我们的 j 因此当我们求到 f[ i ][ j ] 时 f[ i ][ j -x] (x<j) 早已求出。因此我们就能得到我们的状态转移方程即 f[ i ][ j ] = max( f[ i -1][ j ] , f[ i -1][ j -v[i]]+wi ) 。

c++代码:
#include<iostream>
#include<vector>
using namespace std;
int volume[1003];
int value[1003];    //根据数据范围定义体积,价值表示第i个物品的体积,价值 
int ans[1003][1003];//根据数据范围定义当前状态ans[i][j]表示前i个物品在体积不超过j的前提下的最大价值 
int main()
{
	int i,j,N,V;   
	cin>>N>>V;       //定义物品数量和背包体积 
	for(i=1;i<=N;i++)
	{
		cin>>volume[i]>>value[i]; //输入各个物品的体积和价值 
	}
	for(i=1;i<N+1;i++)     //从第一个物品开始递推找前i个物品的各个状态值 
	{
		for(j=0;j<=V;j++)  //求体积从0到V各个状态的值 
		{
			ans[i][j]=ans[i-1][j];//假设第i个物品不选ans[i][j]就等于ans[i-1][j] 
			if(j>=volume[i])      //当体积能装下这个物品时那么这个物品就有可能被选择 
				ans[i][j]=max(ans[i-1][j],ans[i-1][j-volume[i]]+value[i]);
				//此时这个物品选与不选取决于两种状态谁的值更大
		}            
	}
	cout<<ans[N][V]<<endl;//输出我们的答案即前N个物品体积不超过V的情况下的最大价值 
	return 0;
} 
改进我们的代码

观察我们的代码是否可以变得更简洁些呢?我们发现当我们在求 f[ i ][ j ] 时,我们只用到了 f[ i -1][ j ] 和 f[ i-1 ][ j -v[i]] 两个值而我们最终只要能求出 f[N][V] 即可 。 所以我们可以不用二维数组,我们可以用一个一维数组 f[j] 表示前 i 个物品情况下的状态就行了,随着我们i的增加不断更新我们的数组就行了。因为我们要更新这个数组即要不断覆盖原来的值,此时体积就不可以从 0 到 V 开始了因为因为在求 f[j] 可能会用到 f[ j-v[i] ] 所以不能从小到大覆盖 f[j] 因为小的被覆盖了大的就求不出了,所以我们应该从大到小覆盖。

思路如下:

在这里插入图片描述在这里插入图片描述

最终代码:
#include<iostream>
#include<vector>
using namespace std;
int N,V;  
int ans[1003];//根据数据范围定义当前状态ans[j]表示前i个物品在体积不超过j的前提下的最大价值 
int main()
{
	 
	cin>>N>>V;   
	for(int i=0;i<N;i++)
	{
		int volume,value;
		cin>>volume>>value;//输入第i个物品的信息 
		for(int j=V;j>=volume;j--)//体积从大到小遍历到当前体积 
		{
			ans[j]=max(ans[j],ans[j-volume]+value);//转移方程 
		}            
	}
	cout<<ans[V]<<endl;//最后的ans[N]即答案 
	return 0;
} 

二维背包问题

问题重述:

有 N 件物品和一个容量是 V 的背包,背包能承受的最大重量是 M。每件物品只能用一次。体积是 vi,重量是 mi,价值是 wi。

求解将哪些物品装入背包,可使物品总体积不超过背包容量,总重量不超过背包可承受的最大重量,且价值总和最大。
输出最大价值。

输入格式
第一行两个整数,N,V, M,用空格隔开,分别表示物品件数、背包容积和背包可承受的最大重量。

接下来有 N 行,每行三个整数 vi,mi,wi,用空格隔开,分别表示第 i 件物品的体积、重量和价值。

输出格式
输出一个整数,表示最大价值。

数据范围
0<N≤1000
0<V,M≤100
0<vi,mi≤100
0<wi≤1000

思路分析:
在了经典的01背包问题后,那么这个二维背包也就不难了,无非就是在加上一层循环,可以相当于我们对每一种体积都遍历一遍体积或者可以对每一种体积都遍历一遍重量。只要我们最外遍历的是物品里面的循环先后无所谓,因为他们都是物品的属性而已,对于计算机来说它并不知道体积和重量的区别是啥。所以我们的套路就是先遍历物品后依次遍历物品属性,在没有优化我们的代码前我们则需要一个三维数组来存储答案了。现在我们可以用优化的方法,用一个二维数组滚动存储答案。

C++代码:

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	int N,V,M;
	vector< vector<int> >ans;
	cin>>N>>V>>M;//输入规模物品数量、背包的体积和背包的承重 
	ans.resize(V+10,vector<int>(M+10,0));//用容器开辟合适空间的二维数组滚动储存答案也可以直接定义合适大小的二维数组一般多开几个空间
	for(int i=0;i<N;i++)//开始遍历物品 
	{
		int Vi,Mi,Wi;
		cin>>Vi>>Mi>>Wi;//现场输入物品属性体积、重量和价值 
		for(int j=V;j>=Vi;j--)//从大到小遍历体积 
		{//虽然这里的两种循环可以任意换但是二维数组的格式必须和它们的先后一致 
			for(int k=M;k>=Mi;k--)//对每一种体积从大到小遍历重量 
			{
				ans[j][k]=max(ans[j][k],ans[j-Vi][k-Mi]+Wi);//二维状态转移方程找到当前体积当前重量下的最大价值 
			}
		}
	}
	cout<<ans[V][M]<<endl;//输出答案 
	return 0;
} 
0-1背包问题,以及空间优化 什么是0-1背包问题? 有一个容量为 N 的背包,要用这个背包装下物品的价值最大,这些物品有两个属性:体积 w 和价值 v。 定义一个二维数组 dp 存储最大价值,其中 dp[ i ][ j ] 表示前 i 件物品体积不超过 j 的情况下能达到的最大价值。设第 i 件物品体积为 w,价值为 v,根据第 i 件物品是否添加到背包中,可以分两种情况讨论: 第 i 件物品没添加到背包,总体积不超过 j... 阅读详情

相关推荐

背包九讲:动态规划经典问题全解析(一)

本文介绍了动态规划中的经典背包问题,重点讲解了"背包九讲"中的前六种类型:01背包、完全背包、多重背包、混合背包、二维费用背包和分组背包。针对每种背包问题,文章详细说明了其特点、状态转移方程和实现方法,并配有相应的例题代码。其中,01背包需要逆序遍历容量防止重复选取;完全背包可正序遍历允许重复;多重背包有三种优化解法;混合背包需分类处理;二维费用背包增加一维状态;分组背包需确保每组只选一个物品。文章还特别强调了不同背包问题的遍历顺序差异及原因。

豪德又AC啦 1111

二维背包问题(二维0-1背包)

给定n种物品和一背包。物品i的重量是wi,体积是bi,其价值为vi,背包的容量为c,容积为d。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大?在选择装入背包的物品是,对每种物品i只能有两种选择,即装入背包和不装入背包。不能将物品i装入背包多次,也不能只装入部分的物品i。尝试设计一个解决此问题的动态规划算法。

zi_longh的博客 9200

【3D目标检测】MMdetection3d——搭建IS-Fusion环境+nuScenes数据集训练

搭建IS-Fusion环境+nuScenes数据集训练

qq_44703886的博客 2323

动态规划:二维01背包问题

详细讲解二维背包得来的5个步骤

evildoerxmf的博客 1705

ECB oracle——attack

基于ECB oracle的攻击方案前言什么是ECB方案步骤1.确定块大小和明文大小2.暴力破解求明文脚本代码 前言 参考文章:Breaking ECB by prepending your own message. 环境地址:ECB oracle 什么是ECB 分组密码中AES的一种模式(其他还有:CBC、ECB、CTR、OCF、CFB)如图每一块加密是分开的。 方案步骤 1.确定块大小和明文大小 先用一个字符"a"去encrypt返回32个字节的数据(64位16进制)依次用"aa",“aaa”…去en

weixin_44617902的博客 1311

保姆级教程:用STM32H743+TJA1042T玩转FDCAN,CubeMX配置1M/5M双速率通信(附完整代码)

本文提供STM32H743与TJA1042T实现FDCAN双速率通信的保姆级教程,详细讲解CubeMX配置1M/5M双速率通信的全过程,包括硬件连接、时钟树配置、过滤器设置及中断管理,并附完整代码示例,助力开发者快速掌握FDCAN高速通信技术。

weixin_30698297的博客 473

【动态规划】 加体积限制的01背包

此题在最基础的0-1背包问题上加了一个体积限制,其基本思想不变。记录容量为1—c,容积为1—d的背包处理前i的物品的最大价值。考虑能不能装下第i个物品,装得的话考虑值不值得装。用一个回溯来记录选择了哪些物品。

Coco416的博客 373

vuecil3+版本下,兼容ie等不支持es6的低版本浏览器

*综上,完成兼容性涉及到的配置的文件有,对应在页面中查看代码,就不单独附代码了:main.js。

yhr0322的博客 833

背包九讲(01背包,完全背包,二维费用的背包)

完全背包与01背包不一样的是:完全背包中的物品都可以无限次的取,而01背包中的物品只可以取一次,所以完全背包问题中的集合划分会比01背包问题的集合划分多的多的多。如果第i件物品放入背包,则背包容量还剩j-v[i],所以要取前i-1件物品放入背包剩余容量j-v[i]所获得的最大价值f[i-1][j-v[i]]。2.2 如果第i件物品放入背包,则f[i][j]=f[i-1][j-v[i]]+w[i]1.如果当前背包容量j

2302_81590667的博客 767

ECU-TEST 快速入门

ECU-TEST 是由位于德国德累斯顿的TraceTronic公司开发的一款用于嵌入式系统测试验证软件工具。自从2003年首次发布ECU-TEST ,该软件成为了汽车ECU开发的标准工具 ,同时也逐步成为了重型机械和工业自动化开发的标准工具 。该软件是起源自于一个控制单元的系统化测试的项目研究,从而为从德累斯顿工业大学脱离出来的TraceTronic公司奠定了基础。ECU-TEST旨在完成测试案例的规范化、评估、求解和归档。得益于该软件包含大量的自动化测试方法使得测试案例的所有必要功能如创建、求解和评估

wangying202的博客 1万+

Rijndael密码算法

一 什么是Rijndael Rijndael是由比利时密码学家设计的分组密码算法,于2000年被选为新一代的标准密码算法——AES。今后会有越来越多的密码软件支持这种算法。 Rijndael的分组长度和密钥长度可以分别以32比特为单位在128比特和256比特的范围内进行选择。不过在AES的规格中,分组长度固定为128比特,密钥长度只有128、192和256比特三种。 二 Rijndael的加...

实践求真知 1万+

动态规划 背包九讲 01背包的二维费用的背包问题

二维费用的背包问题 有 N 件物品和一个容量是 V 的背包,背包能承受的最大重量是 M。 每件物品只能用一次。体积是 vi,重量是 mi,价值是 wi。 求解将哪些物品装入背包,可使物品总体积不超过背包容量,总重量不超过背包可承受的最大重量,且价值总和最大。 输出最大价值。 输入格式 第一行两个整数,N,V,M,用空格隔开,分别表示物品件数、背包容积和背包可承受的最大重量。 接下来有 N 行,每行三个整数 vi,mi,wi,用空格隔开,分别表示第 i 件物品的体积、重量和价值。 输出格式 输出一个整数,表示

林黛玉到拔垂杨柳的博客 235

从点击图标到Activity亮屏:AMS、Zygote、ActivityThread的Binder协作之旅

Launcher通过Context调用 startActivity(),最终会通过 Activity.startActivity() 传递到 ActivityManager.getService(),获取AMS的Binder代理对象(IActivityManager)。这里的 attach() 方法通过Binder调用AMS的 attachApplication(),将新进程的 IApplicationThread 代理对象传递给AMS。这一步的Binder通信,是整个启动流程的关键转折点,值得细细品味。

大模型大数据攻城狮的专栏 1071

01背包问题,完全背包问题的二维数组,一维数组的解答

关于01背包问题,完全背包问题,这里就不过多阐述。这里只是总结一下这两个问题的二维数组,一维数组的两种表达方式。 为什么要用一位数组,两个原因:1.节约空间(二维变一维)2.时间复杂度降为线性。 直接上代码,如果对01背包问题,完全背包问题有问题的推荐看一下《背包九讲》和其他博客。 背包九讲:https://github.com/tianyicui/pack 01背包问题可视化的网站:http:...

FGY_u的博客 3302

第14.8章 高翔博士最新开源框架Lightning-LM源码解读(八):位姿平滑器PoseSmoother深度剖析,从原理到代码实现

本文深度解析了高翔博士开源框架Lightning-LM中的位姿平滑器PoseSmoother模块。该模块通过设置平滑因子,在保证位姿准确性的同时减少突变,使位姿变化更平稳。文章详细讲解了模块功能、数据流程和核心代码实现,包括构造函数、拷贝构造函数以及关键的PushDRPose和PushPose函数。重点分析了位姿平滑算法原理,涉及运动有效性校验、位姿队列维护和平滑因子调节等核心机制。此外还介绍了相关C++语法(如显式构造函数、默认拷贝构造)和优化方向。本解析为SLAM学习者提供了位姿平滑处理的实用实现范例。

行知SLAM 600

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

刷题巩固-----DAY11(二维费用的背包问题)

今天是背包九讲的第五讲,二维费用的背包问题。与差分,前缀和算法相似,01背包问题也有二维问题,与一维的优化方式一样,都是降低维度。在一维背包问题中,是将二维数组降低为一维,然后滚动数组,倒序遍历,而在二维背包问题中,是将三维数组降低为二维,然后滚动数组,倒序遍历。

2301_79731058的博客 279

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

背包九讲总结

文章目录前言一、01背包(二维分析、一维优化)1.背景2.分析3.代码二、完全背包(与01背包比较)1.背景2.分析3.代码三、多重背包(朴素、二进制优化划分、单调队列优化)1.背景2.分析3.代码四、1.背景2.分析3.代码 前言 <font color=#999AAA 根据y总的视频,总结了一下背包九讲的内容,准备好好搞一下dp问题。 一、01背包(二维分析、一维优化) 1.背景 01背包 先给定背包容积大小V,再给定物品数目N,之后根据N的值输入每个物品的体积v[i]跟价值w[i],问背

qq_52441682的博客 1768

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

背包九讲【进阶版】(上)

本文重新梳理了动态规划中的背包问题,包括01背包、完全背包,多重背包、混合背包和二维费用背包以及各自的优化方式。

2402_88147924的博客 1174

背包习题

2301_81692739的博客 1218

背包焚诀:dp糕手修炼必备

本文介绍了背包九讲经典解法,包括01背包、完全背包、多重背包、分组背包、有依赖的分组背包等。

TS & c++ 1198

dd大牛背包九讲(01,完全,多重,混合,二维,分组等背包)(转载+补充)一万二千字!!!

P01: 01背包问题 题目 有N件物品和一个容量为V的背包。第i件物品的重量是wi,价值是vi。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。 基本思路 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放 用子问题定义状态:即 前i件物品恰(这里很重要,要理解!!!)放入一个容量

Mouse_liang的博客 1216

01背包笔记

01背包    至今看到最好的背包文章是《背包九讲》,不得不佩服作者,本文只是一些重点的入门笔记。    问题描述:V背包容积,n物品数量,v[i]第i件物品的体积,w[i]第i件物品的价值,问背包能装的最大价值?    思路:依次扫描每一件物品,判断该物品取或不取,dp[i][j]表示对第i件物品的判断,[i]中的i表示物品,[j]表示容积,j的增加范围[0

hehehahaxixi_的博客 291

背包问题Java详解版

资料:B站背包九讲:https://www.bilibili.com/video/BV1qt411Z7nE 对应训练题:https://www.acwing.com/problem/ 01背包问题 此问题解法来自背包九讲, 未优化 状态:f[i][j]表示前 i 个物品,总体积为 j 的最大价值 所以就有两种方式,选当前物品放入背包和不选当前物品放入背包 即不选当前物品放入背包 :f[i-1][j],直接拿上一个物品的价值即可,体积不变 或者选当前物品放入背包,:f[i-1][j-v[i]]+w[i],需

AD钙的博客 1126

c++背包九讲之二维费用背包问题

一、背包九讲总述 关于动态规划问题,最典型的就是背包九讲,先理解背包九讲后再总结关于动态规划的问题 1、01背包问题 2、完全背包问题 3、多重背包问题 4、混合背包问题 5、二维费用的背包问题 6、分组背包问题 7、背包问题求方案数 8、求背包问题的方案 9、有依赖的背包问题 往前四篇博文已经介绍了前四个问题,有需要的同学可以看一下!! 二、二维费用背包问题 二维费用的背包问题是指:对于每件...

weixin_42579072的博客 1297

背包九讲3——多重背包问题的理解(Java图解)

多重背包 题目 有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 基本算法 这题目和完全背包问题很类似。基本的方程只需将完全背包问题的方程略微一改即可,因为对于第i种物品有n[i]+1种策略:取0件,取1件……取n[i]件。令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值,则有状态转移方程: f[i][v]=max{f[i-1][v-k*c[i]]+k*w

caigen0001的专栏 1750

01背包 / 完全背包笔记

文章目录*前言**代码实现**初始化问题(一维数组)**求方案数(以01背包为例)**背包方案数例题**背包问题在leetcode中的题目* 前言 观看闫神的背包九讲的一点点笔记 代码实现 01背包的二维实现 // 外层循环是可以选择物品 for(int i=1; i<=n; i++){ // 内层循环时背包的容量 for(int v=w[i]; v<=V;v++){ /* dp[i][v]表示前i个元素总容量为v时最大的价值 对于第i个元素只有两种选择:选or不选,

NFII 245
上一篇: Boolean Expressions题解
下一篇: 背包九讲 之 01背包求方案数
yam bean
博客等级 码龄8年 11粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值