一文教会01背包

01背包问题暴力解法 背包问题暴力解法 阅读详情

01背包

01背包指的是一种题目模板

如果说有很多东西 每个东西只能拿一次 要装到一个背包里 背包有体积上限

这就是经典的01背包问题

在我们下意识背出模板的时候

我们先想一下 01背包问题的暴力解法是什么

在01背包中 对于每件物品 要么取 要么不取 所以一共有2^n种情况

这是回溯+爆搜的做法

为了优化时间复杂度 我们引入了动态规划(DP)

为了解释动态规划

我决定引入一个DP五部曲的概念(——摘自《代码随想录》)

  • 确定dp数组(dp table)以及下标的含义
  • 确定递推公式
  • dp数组如何初始化
  • 确定遍历顺序
  • 举例推导dp数组

下面是01背包的模板题

有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。

第 i件物品的体积是 vi,价值是 wi

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

输入格式

第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。

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

输出格式

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

数据范围

0<N,V≤1000 0<N,V≤1000 0<N,V≤1000

0<vi,wi≤1000 0<vi,wi≤1000 0<vi,wi≤1000

输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
8

朴素的做法是这样的

 	int n, V;
    cin >> n >> V;
    for(int i = 1; i <= n; i++) cin >> v[i] >> w[i];
    
    for(int i = 1; i <= n; i++)
    	for(int j = 1; j <= V; j++)
    	{ 
    		if(j >= v[i])	dp[i][j] = max(dp[i-1][j], dp[i-1][j-v[i]] + w[i]);
    		else	dp[i][j] = dp[i-1][j];
    	}
    	
    cout << dp[n][V] << endl;

对于背包问题其实状态都是可以压缩的

在使用二维数组的时候,递推公式:
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
其实我们发现 如果把dp[i-1]那一层直接拷贝到dp[i] 表达式就可以是:
dp[i][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i]);

压缩后的一维做法

 	int n, V;
    cin >> n >> V;
    for(int i = 1; i <= n; i++) cin >> v[i] >> w[i];
    
    for(int i = 1; i <= n; i++)
    	for(int j = V; j >= w[i]; j--)
            dp[j] = max(dp[j], dp[j - w[i]] + value[i]);
    cout << dp[V] << endl;
我们对01背包进行DP五部曲分析
1.确定dp数组的定义

在一维版的dp数组中,dp[j]代表当体积为j时,所背物品的最大价值

2.递推公式
dp[j] = max(dp[j],  dp[j - weight[i]] + value[j]);
3.对于数组的初始化

关于初始化 我们要考虑到第1点和第2点,在实际问题中 我们一般会把3和4联系在一起想

因为dp[j]表示:容量为j的背包,可以装下的最大价值是dp[j]

那么当j = 0 的时候 什么也装不了 dp[0] = 0;

再来看到递推公式

因为dp数组的意义是最大价值 那么当价值不为负的时候,非0下标初始化为0就可以了

但是当价值为负的时候 ,非0下标必须初始化到负无穷,不然初始值就会覆盖掉最大价值

//插 cpp如何把数组初始化成负无穷
memset(d, 0x8f, sizeof(d));
4.数组遍历的顺序

不同于一些线性DP的问题,背包问题在递推公式并没有直接给出递推的方向

for(int i = 1; i <= n; i++)
	for(int j = V; j >= w[i]; j--)
		dp[j] = max(dp[j], dp[j-w[i]] + value[i]);

这里我们突然发现 滚动数组的遍历写法和二维数组的遍历写法有些不同

为什么内嵌循环的循环顺序是从大到小呢?

答:倒序遍历是因为保证每个物品只被放入背包一次

这里可能有些不太好理解

我们举一个例子:物品0重量w[0] = 1, value[0] = 15;

正序遍历:

dp[1] = dp[1 - weight[0]] + value[0] = 15
dp[2] = dp[2 - weight[0]] + value[0] = 30

物品0被加入了两次,怎么会是呢?

倒序遍历:

dp[2] = dp[2 - weight[0]] + value[0] = 15 (dp数组已经都初始化为0)
dp[1] = dp[1 - weight[0]] + value[0] = 15

从后往前遍历的话,每次取得的状态不会和之前取得的状态发生重叠,这样保证了每件物品加入一次

那么问题又来了,为什么二维数组中不需要倒序遍历呢?

因为二维数组中的dp[i] [j] 都是通过dp[i-1] [j]来得到的,本层的并不会被覆盖

此处较为拗口,建议实践出真知

再来看看两个嵌套for循环的顺序,代码中是先遍历物品嵌套遍历背包容量,那可不可以先遍历背包容量嵌套遍历物品呢?

达咩!

因为一维dp的写法,背包容量一定是要倒序遍历(原因上面已经讲了),如果遍历背包容量放在上一层,那么每个dp[j]就只会放入一个物品,即:背包里只放入了一个物品。

如果你不能理解的话,建议将for循环颠倒一下输出dp数组观察一下

5.举例推导

​ 重量 价值
物品0 1 15
物品1 3 20
物品2 4 30

一维dp,分别用物品0,物品1,物品2 来遍历背包,最终得到结果如下:

第一次遍历物品0 0 | 15 | 15 | 15 | 15

第二次遍历物品1 0 | 15 | 15 | 20 | 35

第三次遍历物品2 0 | 15 | 15 | 20 | 35

【算法】一文带你搞懂0-1背包问题!(理论篇) 详解动态规划中的0-1背包问题原理及应用 阅读详情

相关推荐

DDR内存设计必看:DFI接口协议详解与实战避坑指南(附时序图解析)

本文深入解析了DDR内存设计中连接内存控制器与物理层的DFI接口协议,聚焦于DDR4/DDR5设计的实际痛点。文章详细阐述了协议版本兼容性、时钟架构(匹配频率与频率比系统)、PCB信号完整性设计以及上电初始化与调试等关键环节,为硬件工程师提供了一套从理论到实战的完整避坑指南,并附有时序图解析以助理解。

weixin_29256771的博客 329

1004: 0-1背包问题(暴力求解)

需对容量为c 的背包进行装载。从n 个物品中选取装入背包的物品,每件物品i 的重量为wi ,价值为pi。对于可行的背包装载,背包中物品的总重量不能超过背包的容量,最佳装载是指所装入的物品价值最高。多个测例,每个测例的输入占三行。第一行两个整数:n(n

qq_53436105的博客 988

【大模型】一图看懂3D因果卷积!

本文将系统性地介绍从1D到3D的因果卷积原理,通过直观的动图演示帮助读者理解其工作机制,并重点探讨3D因果卷积在大规模视频生成中的独特价值和应用前景。

xian0710830114的专栏 2197

01背包问题穷举法,暴力破解法(穷举法)递归

穷举法解决01背包利用暴力破解法(穷举法) 问题描述:给定n个重量为{w1, w2, … ,wn}、价值为{v1, v2, … ,vn}的物品和一个容量为C的背包,求这些物品中的一个最有价值的子集,且要能够装到背包中。 包的总容量 物品编号 价值 重量 1 4$ 12kg 2 2$ 2kg 3 2$ 1kg 4 1$ 1kg 5 10$ 4kg 思路: 利用递归进行遍历求出各个的可能性 将遍历出的结果存入int[] back = new int[N],进行缓存 没存入一

qq_44236958的博客 5088

Globus 数据下载

Globus 大数据下载流程~

weixin_43978558的博客 6614

多标签损失之Hamming Loss(PyTorch和sklearn)、Focal Loss、交叉熵和ASL损失

多标签损失

wuli_xin的博客 4460

01背包问题 从暴力到动态规划

1.什么是背包问题? 具体题目 最基本的背包问题就是01背包问题(01 knapsack problem):一共有N件物品,第i(i从1开始)件物品的重量为w[i],价值为v[i]。在总重量不超过背包承载上限W的情况下,能够装入背包的最大价值是多少? 百度百科 背包问题(Knapsack problem)是一种组合优化的NP完全(NP-Complete,NPC)问题。问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能...

qq_41858479的博客 1686

AD9361 Fast Lock实战:Python脚本自动生成Profile寄存器配置(附完整代码)

本文详细介绍了利用Python脚本实现AD9361 Fast Lock Profile寄存器自动化配置的实战方案。通过解析频率合成公式、VCO约束及查表机制,脚本能根据目标频率一键生成完整的16进制寄存器序列,大幅提升射频系统开发中多频点切换的效率和准确性,并支持CSV、JSON、C头文件等多种输出格式,便于与FPGA/嵌入式系统集成。

weixin_29194693的博客 474

暴力/蛮力法经典例题--0/1背包问题--C语言

问题描述: 有n个重量各不相同的物品(物品编号为0~n-1),他们的价值也各不相同,给定一个容量为mw=6的背包,问在能装人背包的物品组合中,最大的价值为多少。

MaxDeCookies的博客 2923

LangChain开发避坑指南:为什么Pylance总提示‘无法解析导入‘?实测7种修复方案

本文深入解析了在VS Code中使用LangChain开发时,Pylance频繁提示‘无法解析导入’的根本原因——Python解释器与语言服务器的环境路径不一致。文章提供了从基础排查到深度配置的7种实测修复方案,包括切换解释器、配置extraPaths、使用pyrightconfig.json等,旨在帮助开发者彻底解决此问题,提升AI应用开发效率。

weixin_28826521的博客 442

TOGAF架构内容—TOGAF 内容框架和企业元模型

TOGAF架构内容—TOGAF 内容框架和企业元模型

深圳市多克创新科技有限公司 1663

Java算法-一文搞懂01背包(小白也能看懂的超详解!!!)

本篇文章详细讲解了"01背包问题",希望能帮助到你。

爱是小小的癌的博客 2549

【现代控制理论期末考点】

现代控制理论期末考点,适用于 SEU Automation

【人工智障 | 计算鸡视觉 | 机器孩】 1444

一文带你轻松弄懂01背包与部分背包问题及其实现

背包问题(Knapsack Problem)作为一类经典的组合优化问题,广泛应用于资源分配、投资决策、装载规划等实际场景。本文我将深入探讨背包问题的两种基本形式:01背包问题和部分背包问题,详细解析其问题定义、算法思路、实现代码及应用场景,通过Python、C++和Java三种语言的实现,带你全面掌握这两类问题的解决方法

1588

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

01背包、完全背包、多重背包、分组背包问题,一文读懂

背包问题是一种组合优化的 NP 完全问题:有 N 个物品和容量为 W 的背包,每个物品都有 自己的体积 w 和价值 v,求拿哪些物品可以使得背包所装下物品的总价值最大。 0-1背包 有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。 每件物品都有选与不选两种情况,那么这个问题完全可以用回溯法来暴力搜索,时间复杂度为O(n2)O(n^2)O(n2),因为暴力解法时间复杂度太高,所以才要用

Kepler11的博客 4362

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

【算法】一文带你搞懂完全背包!(附背包问题总结)

详解动态规划中的完全背包问题原理及应用,了解多重背包,以及总结笔试面试中解决背包问题的关键。

Conner7的博客 7442

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

01背包问题一文讲通(01背包代码以及优化思想)

简单点来说就是挑选出一个部分,然后枚举每一种方案,在这个部分中求取题目所规定的最优解作为局部最优解,再在局部最优解中挑选出一些组成下一部分的最优解(比如说有n种货物,每种货物有m个,每个货物有w重量与v价值,最多拿重量为k的物品,那我们就可以把这堆货物规划成n个部分,每个部分包含了挑选前i个货物的所有情况,在这里面一层一层递进求解答案。

xixishuiba_CD的博客 1022

一文看懂3种背包问题

前言 前面在动态规划详解一文种讲解了几个动态规划的基本问题。最近在工作中碰到了背包问题,写了一下基于动态规划的算法,决定写一篇文章总结一下。 3种背包问题的比较 背包问题:有N种物品和一个容量为b的背包,第i种物品的重量为,价值为,如何选择放入的物品使得总价值最大。 根据每件物品的数量限制,就分为3种背包问题,定义如下: 01背包:每种物品只有一件,要么选择放入,要么选择不放入 完全背...

大鹏的blog 4673

完全背包与01背包

这个转移的状态V[i][j]的含义即在考虑第0--i个物品时,容量为j的背包所能承载的最大价值。首先,当背包容量j

qq_42987967的博客 892

一文彻底搞懂背包问题

详解01背包,多重背包的二维数组解法和一维数组解法,容易踩的坑

阿钊侃技术的博客 1098

一文讲解01背包问题

一文搞懂01背包问题

m0_60406551的博客 2052

完全背包一文讲通(完全背包代码以及优化思想)

完全背包,也就是每种物品可以取无限次(我也不知道为什么这么叫QWQ)。

xixishuiba_CD的博客 974

C++ 01背包

C++01背包讲解:通俗易懂,包教包会

qq_57837348的博客 891

一文解析动态规划中的背包问题

01背包问题 + 完全背包问题 完全背包是由01背包稍作变化而来,即:完全背包的物品数量是无限的。 01背包问题是一个物品只能用一次,完全背包问题是一个物品可以用无数次。 二维数组处理01背包问题 01 背包 有N件物品和一个最多能被重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。 这是标准的背包问题,以至于很多同学看了这个自然就会想到背包,甚至都不知道暴力的解法应该怎么解了。 这样其实是没有从底向上

毛毛的专栏 1156

背包算法轻松搞定——01背包算法、部分背包算法

这篇文章过程讲得很详细,一文搞懂(点击看原文) 不懂之前觉得很难理解,觉得很复杂,其实没有必要。因为只要懂动态规划就可以很轻松搞定0-1背包算法(部分背包算法更简单,排序即可)。之前看了很多篇文章都觉得太难了,好复杂,其实只是每个人逻辑思维不一样,别人说的你不一定能理解,但是多看几篇文章,总有一片你能轻易理解(就像上面那篇,一看懂)。 进入正题,由于上面的文章讲得很详细了,建议大家都去看上面的...

YangJiaJun0506的博客 2091

一文彻底搞懂01背包算法

0-1 背包问题:给定 n 种物品和一个容量为 C 的背包,物品 i 的重量是 wiwiw_i,其价值为 viviv_i 。 问:应该如何选择装入背包的物品,使得装入背包中的物品的总价值最大? 假设一个函数B是求解总价值的函数,有两个因变量n与C ;则我们的优化目标就变为 max.F(n,C,x).x∈0,1max.F(n,C,x).x∈0,1max.F(n,C,x) .x\in{{0,1}...

u014296502的专栏 2万+
上一篇: B. Make AP
下一篇: 根据数据范围来推断该使用的算法
a simple_boy
博客等级 码龄5年 1粉丝 50原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值