01背包问题

算法导论【近似算法】—0-1背包问题的近似算法 若对于每一个固定的ϵ0ϵ > 0ϵ0,算法 A 的运行时间以实例III的规模的多项式为上界,则称 A 是一个多项时间近似方案。在 PTAS 的基础上,进一步要求算法 A 的运行时间以实例III的规模和1ϵ1 / ϵ1/ϵ的多项式为上界,则称 A 是一个完全多项时间近似方案。FPTAS 被认为是最值得研究的近似算法,仅有极少数的 NP-hard 问题存在 FPTAS。 阅读详情

前言

本文主要针对01背包的解决方法以及思路。
先介绍一下dp问题的本质:通过局部最优解达到全局最优解,避免不必要的重复计算(也就是冗余),注意:动态规划不是搜索,所以可以用较短的时间解决问题。
dp问题一般具有以下特性:

  1. 子问题和主问题相似,具有相同的数据结构
  2. 通过合理规划子问题的最优解,以达到全局情况的最优解

01背包

01背包是这么个问题(如果已了解过可跳过本部分):
有 n n n件物品,每件物品都有两种属性:价值 C C C 和重量 W W W。
背包也有一个给定的载重量 M M M,并且背包内物品的总重量不可以超过 M M M。
求能获得的最大总价值。

输入
第一行:两个整数, M M M(背包容量, M < = 200 M<=200 M<=200)和 N N N(物品数量, N < = 30 ) N<=30) N<=30);
第 2 ⋯ N + 1 2\cdots N+1 2⋯N+1 行:每行二个整数 W i W_i Wi​, C i C_i Ci​,表示每个物品的重量和价值。
输出
仅一行,一个数,表示最大总价值。


这里是样例题目链接:01背包题目链接

思路

为了方便,我先把题目的自测数据打在这里:

输入

10 4
2 1
3 3
4 5
7 9

输出

12

解释

选择第三、第五件物品,总重量为 10 10 10,总价值为 12 12 12。


这里主要分析一下思路。
我们可以假定一开始背包的重量是 0 0 0,然后慢慢累加到 M M M。
还假定一开始物品的数量为 0 0 0件,然后慢慢累加到 n n n件。
这就需要一个二维数组,我们姑且称它为 d p [ ] [ ] dp[][] dp[][](这里方括号内的数随便你怎么填,只要满足题目大小就行。第一个方括号代表物品数量(或者也可以理解为第 i i i 个物品),第二个方括号代表背包大小)。
二维dp数组的表格形式:

物品数量背包容量答案
000
⋯ \cdots ⋯ ⋯ \cdots ⋯ ⋯ \cdots ⋯
n n n m m m最终答案

数组 w w w和 c c c的表格形式:

重量价值
w 1 w_1 w1​ c 1 c_1 c1​
⋯ \cdots ⋯ ⋯ \cdots ⋯
w n w_n wn​ c n c_n cn​

很显然 d p [ 0 ] [ 0 ] = 0 dp[0][0]=0 dp[0][0]=0,原因有两个,但重点是:背包装得下吗?(对于 d p [ 0 ] [ 0 ] dp[0][0] dp[0][0],明显装不下,因为题目保证物品重量 ≥ 0 \ge 0 ≥0)。
然后再进一步:对于任何 d p [ i ] [ 0 ] dp[i][0] dp[i][0]肯定都等于 0 0 0,因为背包容量为 0 0 0的背包肯定装不下任何东西。
初始化数据完成后,可以开始递推了。
使用 f o r for for循环遍历 d p dp dp数组:

for (int i = 1; i <= n; ++i) {
	for (int j = 1/* 以后会优化 */; j <= n; ++j) {
		// 递推代码
	}
}

递推代码

我们来想一想:什么时候背包的价值可以增加?
就是当容量足够的时候。
所以从 d p [ i ] [ w [ i ] ] dp[i][w[i]] dp[i][w[i]]开始,总价值就发生变化:它可以增加了。但是真的只要加就好了吗?并不是的。
在这里我们就要引进状态转移方程式了,我们暂时先不讨论它在01背包中是什么形态。
但大致意思就是:选择当前子问题中最好的决策。
在本问题中,分两种情况讨论:

  1. 不可以装下物品时, d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i−1][j]。
    因为装不下等于没有,所以就是没有这件物品时的最优解。
  2. 当可以装下物品( j ≥ w [ i ] j\ge w[i] j≥w[i])时,又有了两种选择:
    选还是不选?
    2.1 选:那么退回 d p [ i − 1 ] [ j − w [ i ] ] + c [ i ] dp[i-1][j-w[i]]+c[i] dp[i−1][j−w[i]]+c[i],也就是没装此物品前(注意这里背包的载重量要减去该物品的重量,因为得腾出来空间装这件物品嘛)然后加上该物品的价值(要不然你就亏了,而且代码在一般情况下不会通过)。这就是选的最大值。
    2.2 不选:那么还是 d p [ i − 1 ] [ j ] dp[i-1][j] dp[i−1][j]

最后做个比较:谁大选谁
这就是 d p [ i ] [ j ] dp[i][j] dp[i][j] 的推法。

最后输出答案就行了。这一步输出 d p [ n ] [ m ] dp[n][m] dp[n][m]

代码

#include <iostream>
using namespace std;

int main()
{
    int n, m;
    cin >> m >> n;
    int w[35], c[35], dp[35][205]; // 请根据需求而定
    for (int i = 1; i <= n; ++i) cin >> w[i] >> c[i];
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (j < w[i]) dp[i][j] = dp[i - 1][j]; // 装不下
            else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + c[i]); // 装得下,做最优决策(这其实就是状态转移方程式)
        }
    }
    cout << dp[n][m];
}

优化

首先让我们再深入一层了解一下dp:
它具有一个关键性质:后无效性原则。
说白了就是前面的操作都不会影响这一步的最优决策。
这也是为什么无论你按照怎么样的顺序去输入这些物品它总能够给你最优答案的原因之一。
我们可以利用这个性质把 d p dp dp 数组压缩成一维。
既然前面的(不包括第 i − 1 i-1 i−1 行)数据对目前这个格子的数据没有影响,那么完全不需要去储存,储存前面无影响力的数据将会造成空间上的巨大浪费。
但是如果将它压缩,数据就会重叠,所以我们不能这么干?
其实解决这个问题可以使用逆推( j = m → 0 j=m\rightarrow 0 j=m→0)。
而且这么做还给我们提供了别的方便.
之前有个判断装不装得下的 i f if if 语句。现在我们可以删掉它了,因为现在的情况与之前有所不同的是:现在所处行已经自动 “继承” 了上一行,现在可以改为 j = m → w [ i ] j=m\rightarrow w[i] j=m→w[i] ,并压缩状态转移方程式。
状态转移方程式(优化版):
d p [ j ] = m a x ( d p [ j ] , d p [ j − w [ i ] ] + c [ i ] ) dp[j] = max(dp[j], dp[j-w[i]]+c[i]) dp[j]=max(dp[j],dp[j−w[i]]+c[i])

新代码(优化版)

#include <bits/stdc++.h>
using namespace std;
int n, m;
int w[110], c[110], dp[1010];
int main() {
    cin >> m >> n;
    for (int i = 1; i <= n; ++i) cin >> w[i] >> c[i];
    for (int i = 0; i <= n; ++i)
        for (int j = m; j >= w[i]; --j)
            dp[j] = max(dp[j], dp[j - w[i]] + c[i]);
    cout << dp[m] << endl;
}

有问题或者建议欢迎在评论区指出。

【0-1背包问题 】详细解析+图解+详细代码 【0-1背包问题】有n 个物品,它们有各自的重量和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?1.【题目描述】2.【递推思路】1.【基本思路】2.【本题思路】3.【图解】3.【代码】 1.【题目描述】 有n 个物品,它们有各自的重量和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和? 物品数量4 背包容量8 物品编号 1 2 3 4 重量 2 3 4 5 价值 3 4 5 8 2.【递推思路】 1.【基本思路】 1.确定状态变量(函数) 2. 阅读详情

相关推荐

知识图谱的数据挖掘与分析

1. 背景介绍 1.1 数据挖掘的崛起 随着互联网的普及和大数据技术的发展,数据挖掘已经成为了计算机科学领域的热门研究方向。数据挖掘是从大量的、不完全的、有噪声的、模糊的、随机的实际应用数据中,通过计算机科学、统计学、信息论等多学科交叉的方法,挖掘出有用信息和知识的过程。数据挖掘的目标是从数据中发现有

AI天才研究院 1600

伪代码——01背包问题

【代码】伪代码——01背包问题。

qq_43522822的博客 1205

Verilog仿真时读取bin文件模拟输入数据流,将输出数据流写入bin文件

需要关注的是,一般会省略文件起始地址和读取长度,那么mem为多大,就会从文件中读取多大的数据出来填充mem。如果只需要读取一次文件,那么代码到此就结束了,但是如果还需要每一帧都读取该文件转换为数据流,则在循环里判断新的一帧信号是否到来,在新的一帧再次打开一次文件,从头开始读取数据。

qq_41137205的博客 2772

动态规划-背包问题

算法、背包问题、动态规划

qq_52147470的博客 3090

PT静态时序分析实战:从基础命令到高级报告解析

本文详细介绍了PT(PrimeTime)静态时序分析(STA)的实战技巧,从基础命令如pt_shell和report_timing的使用,到高级报告解析与问题排查。通过丰富的实例和脚本示例,帮助工程师快速掌握时序分析的核心技能,提升芯片设计验证效率。

weixin_29289821的博客 954

CCD成像原理以及机器视觉中的相机选型

CCD成像原理以及机器视觉中的相机选型 近年来,随着人工智能的高速发展和图像处理技术的日益成熟,机器视觉在自动化领域发挥着越来越大的作用。机器视觉被用于代替人工视觉,使机器人能够完成以往只有人工才能完成的任务,这大大减少了在危险环境下工作的风险。同时,在来料无序或工作环境杂乱的情况下,机器视觉可以显著提高生产效率和自动化柔性程度。随着人们对工业设计水平和生产效率需求的日益提高,机器视觉正在逐步代替传统复杂繁琐的自动化模式,成为当今的主要发展趋势。 机器视觉是一项综合的技术,包括数字图像处理,传感器,光学

cszn6666的博客 5571

【动态规划】背包问题

注意:for j in range(1,m+1):是枚举所有的情况,不用一一判断放入物品后背包容量减少后j的变化。为什么从1开始,因为0已经写出来了,即dp[i-1][j]=dp[i-1][j-0*a[i-1]]+0*v[i-1]。 01背包无价值 n=len(a) dp=[[False]*(m+1) for i in range(n+1)] dp[0][0]=True for i in range(1,n+1): dp[i][0]=True for j in range(1,m+1)

he_Microsoft的博客 1186

AI:Coze、Dify、n8n:三款低代码工具如何选?

Coze、Dify、n8n:三款低代码工具如何选?

Kant2048的博客 2806

动态规划之01背包问题

对 01背包的详细讲解,推荐观看。

Jiguoyuanyic的博客 2808

验证码破解2.0:Python+CV大模型搞定滑块/点选验证

核心创新:基于YOLOv8+SAM CV大模型的端到端验证码破解方案,无需人工设计特征,适配多种验证码类型;核心价值高成功率:滑块验证≥95%,点选验证≥90%,远超传统CV方案;低延迟:单验证码破解≤2秒,满足高并发采集需求;行为模拟:生成符合人类操作的轨迹,绕过行为检测;易扩展:统一架构支持新增验证码类型,仅需少量标注数据微调;技术要点采用YOLOv8实现快速目标检测,SAM实现像素级分割;生成物理规律的人类轨迹,模拟真实操作行为;

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1261

国产数据库全解析:openGauss、OceanBase、TiDB与KingbaseES的核心优势与应用场景指南

本文将深入剖析openGauss、OceanBase、TiDB和KingbaseES这四款主流国产数据库的核心内容,并针对国产化过程中给出使用建议,以帮助企业根据自身需求选择合适的数据库解决方案。国产数据库在性能、扩展性、兼容性、安全性等方面展现出强大实力,能够满足不同行业、不同场景的需求。企业在进行国产化过程中,应充分考虑业务特点、技术栈、团队能力等因素,结合上述分析,选择最适合自身的国产数据库产品。随着国产数据库技术的持续发展与生态完善,它们将成为推动企业数字化转型、保障数据安全的重要力量。

java专栏 8779

分支界限——01背包问题

01背包问题 背包问题是著名的NP完全问题,在实际生活中有广泛的应用。01背包是背包问题中的一种,也是较简单的一种,有很多种算法可以求解01背包问题,这里介绍利用分支界限的算法。 问题描述 设有n个物品,他们具有各自的重量w和价值v;给定一个具有一个容量W的背包,求将物品有选择的放入背包中,使得装入的物品的价值之和最大? 01背包:物品是完整个体,只存在放或不放两种状态,不能放入一部分。 分析设计...

Mr.DImple的博客 4979

com.sap.aii.af.service.cpa.CPAObjectNotFoundException: Couldn‘t retrieve inbound binding

错误消息:错误截图:该错误通常表示在集成配置中,未找到与特定消息匹配的入站绑定(Inbound Binding)。具体而言,错误消息中的 P/S/A(Party/Service/Action)值未在配置中找到对应的入站绑定。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 373

【动态规划】01背包问题

【动态规划】01背包问题

一个专注于客户端开发的技术er,不定期更新Android,Flutter,HormonyOS等方向的使用心得和感悟 6843

计算机控制技术及应用

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

visio安装包

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

01背包问题详解

什么是背包问题 最常见的背包问题有01背包,完全背包,多重背包,分组背包这四种。什么是背包问题?简单来说就是:一个小偷背了一个背包潜进了金店,包就那么大,他如果保证他背出来所有物品加起来的价值最大。 背包问题属于动态规划,解决动态规划问题一般以下图方式来考虑 01背包问题 01背包问题含义是N个物品,容量V背包,每件物品仅用一次 例题:AcWing 2.01背包问题 有 N件物品和一个容量是 V的背包。每件物品只能使用一次。 第 i 件物品的体积是 vi,价值是wi。 求解将哪些物品装入

zgdlxs的博客 2万+

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

01背包问题讲解

1.什么是01背包问题? 2.01背包问题的解决思路以及原理 3.C++代码实现01背包问题

qq_21230831的博客 1490

SAP B1中文培訓教材_SDK

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

C++ 01背包问题

问题简单重述 有N件物品和容量为W的背包,每件物品只能使用一次。 设第i件物品的价值为v(i),第i件物品的重量为 w(i)。 求解: 问应将哪些物品放入背包中,在不超过最大容量的情况下使得总价值最大? 以下为 C++代码 #include<bits/stdc++.h> using namespace std; const int L = 1e5; int v[L+1],w[L+1],f[L+1]; clock_t start ,stop; int main(){ int N,V;

一夜星尘 8600

01背包问题&&完全背包问题

01背包问题 问题描述:有N件物品,每件物品的重量为w[i],价值为c[i],现有一个容量为V的背包,问如何选取物品放入背包中,使得物品的总价值最大。其中每种物品都只有1件。 输入: 5 8 //物品数 最大容量 3 4 //每件物品的重量 每件物品的价值 5 5 1 2 2 1 2 3 输出:10 完全背包问题 问题描述:有N件物品,每件物品的重量为w[i],价值...

jelly的博客 1798

动态规划——背包问题(01背包问题)

动态规划 01背包

qq_43903506的博客 4383

01背包问题VS完全背包问题

01背包问题: 每个物品只能选择一次,给定背包的最大承重量total和每个物品i的重量weight[i]和价值value[i],求背包可以装下的最大价值 #include<iostream> #include<vector> using namespace std; int main() { int num, total; cin >> num &...

weixin_40679061的博客 3973

分支限界法01背包问题_01背包问题

最近在做调度系统相关的事情,看到论文中描述通过最大流来解决调度的整体最优。然后我们尝试使用背包问题来解决,背包问题能不能解决调度最优不重要,重要的是我看到网上描述的背包问题的解法容易把人看蒙圈了,所以我做个视频讲一下01背包问题。1.01背包问题的描述有n个不可分割的物品,它们有各自的重量和价值,现有固定容量的背包,选择把哪些物品放入背包可以让背包中物品的价值最大。2.错觉按照价值和重量...

weixin_35390150的博客 1044

01数据结构-01背包问题

当我们要在背包容量为2的情况下放入物品id1的时候,我们要么不放入1,此时最优结果F(0,2)是图中橙色区域对应部分,要么放入1,此时最优结果是放入1后1的价值加上背包容量减去1的重量的背包容量作为F()的参数,即F(0,0)图中绿色部分,明显0+10>6,所以此时我们填写的是10。如图,同理当背包容量为0的时候,1号和2号物品也放不进去,当背包容量为1的时候,此时我们可以有两种选择,一种是选择不放1,那么最优值是F(0,1),如果放入物品2,发现物品2重2放不进去,我们取最优解,肯定是F(0,1)。

2302_82136376的博客 1108
上一篇: template模板函数之用法及实践
下一篇: 完全背包问题
peter_code
博客等级 码龄5年 41粉丝 22原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值