0-1背包问题
1、简介假设我们有n件物品分别编号为1, 2...n。其中编号为i的物品价值为vi它的重量为wi。为了简化问题假定价值和重量都是整数值。现在假设我们有一个背包它能够承载的重量是W。现在我们希望往包里装这些物品使得包里装的物品价值最大化那么我们该如何来选择装的东西呢问题结构如下图所示这个问题其实根据不同的情况可以归结为不同的解决方法。假定我们这里选取的物品每个都是独立的不能选取部分。也就是说我们要么选取某个物品要么不能选取不能只选取一个物品的一部分。这种情况我们称之为0-1背包问题。而如果我们可以使用部分的物品的话这个问题则成为部分背包(fractional knapsack)问题。这里我们只考虑0-1背包问题。2、初步分析对于这个问题一开始确实有点不太好入手。一堆的物品每一个都有一定的质量和价值我们能够装入的总重量有限制该怎么来装使得价值最大呢对于这n个物品每个物品我们可能会选也可能不选那么我们总共就可能有2^n种组合选择方式。如果我们采用这种办法来硬算的话则整体的时间复杂度就达到指数级别的肯定不可行。现在我们换一种思路。既然每一种物品都有价格和重量我们优先挑选那些单位价格最高的是否可行呢比如在下图中我们有3种物品他们的重量和价格分别是10, 20, 30 kg和60, 100, 120。那么按照单位价格来算的话我们最先应该挑选的是价格为60的元素选择它之后背包还剩下50 - 10 40kg。再继续前面的选择我们应该挑选价格为100的元素这样背包里的总价值为60 100 160。所占用的重量为30, 剩下20kg。因为后面需要挑选的物品为30kg已经超出背包的容量了。我们按照这种思路能选择到的最多就是前面两个物品。如下图按照我们前面的期望这样选择得到的价值应该是最大的。可是由于有一个背包重量的限制这里只用了30kg还有剩下20kg浪费了。这会是最优的选择吗我们看看所有的选择情况很遗憾在这几种选择情况中我们前面的选择反而是带来价值最低的。而选择重量分别为20kg和30kg的物品带来了最大的价值。看来我们刚才这种选择最佳单位价格的方式也行不通。3、动态规划思路既然前面两种办法都不可行我们再来看看有没有别的方法。我们再来看这个问题。我们需要选择n个元素中的若干个来形成最优解假定为k个。那么对于这k个元素a1, a2, ...ak来说它们组成的物品组合必然满足总重量背包重量限制而且它们的价值必然是最大的。因为它们是我们假定的最优选择嘛肯定价值应该是最大的。假定ak是我们按照前面顺序放入的最后一个物品。它的重量为wk它的价值为vk。既然我们前面选择的这k个元素构成了最优选择如果我们把这个ak物品拿走对应于k-1个物品来说它们所涵盖的重量范围为0-(W-wk)。假定W为背包允许承重的量。假定最终的价值是V剩下的物品所构成的价值为V-vk。这剩下的k-1个元素是不是构成了一个这种W-wk的最优解呢我们可以用反证法来推导。假定拿走ak这个物品后剩下的这些物品没有构成W-wk重量范围的最佳价值选择。那么我们肯定有另外k-1个元素他们在W-wk重量范围内构成的价值更大。如果这样的话我们用这k-1个物品再加上第k个他们构成的最终W重量范围内的价值就是最优的。这岂不是和我们前面假设的k个元素构成最佳矛盾了吗所以我们可以肯定在这k个元素里拿掉最后那个元素前面剩下的元素依然构成一个最佳解。现在我们经过前面的推理已经得到了一个基本的递推关系就是一个最优解的子解集也是最优的。可是我们该怎么来求得这个最优解呢我们这样来看。假定我们定义一个函数c[i, w]表示到第i个元素为止在限制总重量为w的情况下我们所能选择到的最优解。那么这个最优解要么包含有i这个物品要么不包含肯定是这两种情况中的一种。如果我们选择了第i个物品那么实际上这个最优解是c[i - 1, w-wi] vi。而如果我们没有选择第i个物品这个最优解是c[i-1, w]。这样实际上对于到底要不要取第i个物品我们只要比较这两种情况哪个的结果值更大不就是最优的么在前面讨论的关系里还有一个情况我们需要考虑的就是我们这个最优解是基于选择物品i时总重量还是在w范围内的如果超出了呢我们肯定不能选择它这就和c[i-1, w]一样。这里有一点值得注意这里的wi指的是第i个物品的重量而不是到第i个物品时的总重量。另外对于初始的情况呢很明显c[0, w]里不管w是多少肯定为0。因为它表示我们一个物品都不选择的情况。c[i, 0]也一样当我们总重量限制为0时肯定价值为0。这样基于我们前面讨论的这3个部分我们可以得到一个如下的递推公式有了这个关系我们可以更进一步的来考虑代码实现了。我们有这么一个递归的关系其中后面的函数结果其实是依赖于前面的结果的。我们只要按照前面求出来最基础的最优条件然后往后面一步步递推就可以找到结果了。我们再来考虑一下具体实现的细节。这一组物品分别有价值和重量我们可以定义两个数组int[] v, int[] w。v[i]表示第i个物品的价值w[i]表示第i个物品的重量。为了表示c[i, w]我们可以使用一个int[i][w]的矩阵。其中i的最大值为物品的数量而w表示最大的重量限制。按照前面的递推关系c[i][0]和c[0][w]都是0。而我们所要求的最终结果是c[n][w]。所以我们实际中创建的矩阵是(n 1) x (w 1)的规格。Python代码实现import numpy as np def solve(vlist,wlist,totalWeight,totalLength): resArr np.zeros((totalLength1,totalWeight1),dtypenp.int32) for i in range(1,totalLength1): for j in range(1,totalWeight1): if wlist[i] j: resArr[i,j] max(resArr[i-1,j-wlist[i]]vlist[i],resArr[i-1,j]) else: resArr[i,j] resArr[i-1,j] return resArr[-1,-1] if __name__ __main__: v [0,60,100,120] w [0,10,20,30] weight 50 n 3 result solve(v,w,weight,n) print(result)5、复杂度优化以上方法的时间和空间复杂度均为 O(N*W)其中时间复杂度基本已经不能再优 化了但空间复杂度却可以优化到 O(W)。先考虑上面讲的基本思路如何实现肯定是有一个主循环 i1..N每次算出来 二维数组 f[i][0..W]的所有值。那么如果只用一个数组 f[0..W]能不能保证 第 i 次循环结束后 f[w]中表示的就是我们定义的状态 f[i][w]呢?f[i][w]是由 f[i-1][w]和 f[i-1][w-c[i]]两个子问题递推而来能否保证在推 f[i][w]时(也 即在第 i 次主循环中推 f[w]时)能够得到 f[i-1][w]和 f[i-1][w-w[i]]的值呢? 事实上这要求在每次主循环中我们以 vV..0 的顺序推 f[w]这样才能保证推 f[v]时 f[v-w[i]]保存的是状态 f[i-1][w-w[i]]的值。改进后的代码如下def solve2(vlist,wlist,totalWeight,totalLength): resArr np.zeros((totalWeight)1,dtypenp.int32) for i in range(1,totalLength1): for j in range(totalWeight,0,-1): if wlist[i] j: resArr[j] max(resArr[j],resArr[j-wlist[i]]vlist[i]) return resArr[-1] if __name__ __main__: v [0,60,100,120] w [0,10,20,30] weight 50 n 3 result solve2(v,w,weight,n) print(result)6、进一步思考我们看到的求最优解的背包问题题目中事实上有两种不太相同的问法。有的题 目要求“恰好装满背包”时的最优解有的题目则并没有要求必须把背包装满。 一种区别这两种问法的实现方法是在初始化的时候有所不同。如果是第一种问法要求恰好装满背包那么在初始化时除了 f[0]为 0 其它 f[1..W]均设为-∞这样就可以保证最终得到的 f[N]是一种恰好装满背包的最 优解。如果并没有要求必须把背包装满而是只希望价格尽量大初始化时应该将 f[0..W]全部设为 0。为什么呢?可以这样理解:初始化的 f 数组事实上就是在没有任何物品可以放入 背包时的合法状态。如果要求背包恰好装满那么此时只有容量为 0 的背包可能 被价值为 0 的 nothing“恰好装满”其它容量的背包均没有合法的解属于未 定义的状态它们的值就都应该是-∞了。如果背包并非必须被装满那么任何 容量的背包都有一个合法解“什么都不装”这个解的价值为 0所以初始时状 态的值也就全部为 0 了。这个小技巧完全可以推广到其它类型的背包问题后面也就不再对进行状态转移 之前的初始化进行讲解。7、总结01 背包问题是最基本的背包问题它包含了背包问题中设计状态、方程的最基 本思想另外别的类型的背包问题往往也可以转换成 01 背包问题求解。故一 定要仔细体会上面基本思路的得出方法状态转移方程的意义以及最后怎样优 化的空间复杂度

相关新闻

C++为什么要重写拷贝函数和重载=

C++为什么要重写拷贝函数和重载=

因为如果我们不重新安排这2个东西,它会直接用号一一对应起来,这就会造成一个问题,如果类中有指针成员,若赋值一方出现了改动,就会造成被复制方的改动,这个显然是地址拷贝,会造成一些bug,所以jav…

2026/7/28 18:36:09阅读更多 →
python常用模块

python常用模块

import(modulename):导入模块 math >>> import math 1、向上取整 math.ceil() >>> num 3.14 >>> math.ceil(num) 42、向下取整 math.floor() >>> num 5.9 >>> math.floor(num) 5 #或 >>> int(num) …

2026/7/28 18:36:09阅读更多 →
Shell脚本入门(一)基础语法

Shell脚本入门(一)基础语法

目录 1、Shell解析器 2、变量 3、运算符 4、条件判断 5、流程控制 6、read函数 1、Shell解析器 默认在CentOS使用的是bash 2、变量 2.1 系统变量 $USER、$SHELL、$HOME、$PWD 2.2 自定义变量 ①定义变量: 变量值 注意:等号两边不能有空格。 ②…

2026/7/28 18:34:08阅读更多 →
提示词驱动的AI Agent:CLI-Anything技术解析

提示词驱动的AI Agent:CLI-Anything技术解析

1. CLI-Anything 的本质:提示词驱动的AI Agent 当我第一次看到CLI-Anything这个项目时,最让我震惊的是它完全颠覆了传统命令行工具的开发模式。作为一个长期从事CLI工具开发的工程师,我习惯性地去GitHub仓库里寻找核心引擎代码,结…

2026/7/28 20:58:49阅读更多 →
语言模型遗忘机制的低秩关联分析与优化策略

语言模型遗忘机制的低秩关联分析与优化策略

1. 项目概述:语言模型遗忘现象的低秩关联解析 在2025年NIPS会议上发表的这项研究,直指大语言模型(LLM)领域一个长期被忽视却至关重要的问题——模型在学习新知识时对旧知识的遗忘机制。我们团队通过低秩矩阵分解技术,首…

2026/7/28 20:58:49阅读更多 →
特泊替尼治疗METex14跳跃突变NSCLC的临床价值

特泊替尼治疗METex14跳跃突变NSCLC的临床价值

1. 项目概述:METex14跳跃突变NSCLC的一线治疗新选择 最近在肺癌靶向治疗领域,特泊替尼(Tepotinib)针对METex14跳跃突变非小细胞肺癌(NSCLC)的一线治疗数据引起了广泛关注。作为一名长期跟踪肺癌精准治疗进展的临床医生,我想结合最新研究数据和…

2026/7/28 20:58:49阅读更多 →
大语言模型(LLM)核心架构与应用实践解析

大语言模型(LLM)核心架构与应用实践解析

1. 从"超级背书侠"到"职场多面手":大语言模型的本质解析 十年前我第一次接触自然语言处理时,系统连简单的主谓宾结构都分析得磕磕绊绊。如今打开手机,AI助手能流畅地帮我写邮件、改代码甚至做心理疏导。这种跨越式发展的…

2026/7/28 20:58:49阅读更多 →
MMDetection3D框架与3D目标检测核心技术解析

MMDetection3D框架与3D目标检测核心技术解析

1. MMDetection3D框架全景解析 作为当前最主流的3D目标检测开源框架之一,MMDetection3D建立在PyTorch生态之上,继承了MMDetection的优秀设计理念。这个框架最显著的特点是采用了高度模块化的架构设计,将整个3D检测流程拆解为可插拔的组件。在…

2026/7/28 20:58:49阅读更多 →
游戏化学习工具Code Quest如何提升C语言入门效率

游戏化学习工具Code Quest如何提升C语言入门效率

1. 为什么游戏化学习工具适合C语言入门?作为一名有十年编程教学经验的开发者,我见证过太多初学者在C语言门槛前放弃。传统教材往往从晦涩的指针和内存管理开始,而今天要介绍的这款名为"Code Quest"的游戏化学习工具,彻底…

2026/7/28 20:56:49阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/28 4:06:39阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/28 2:08:06阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/28 1:38:28阅读更多 →
告别臃肿!3步让你的暗影精灵笔记本重获新生

告别臃肿!3步让你的暗影精灵笔记本重获新生

告别臃肿!3步让你的暗影精灵笔记本重获新生 【免费下载链接】OmenSuperHub Control Omen laptop performance, fan speeds, and keyboard lighting, and unlock power limits. 项目地址: https://gitcode.com/gh_mirrors/om/OmenSuperHub 你是否也曾为官方Om…

2026/7/28 0:00:29阅读更多 →
RAG必踩坑!财报法规检索不准?这款开源工具让答案浮出水面,准确率飙升98.7%!

RAG必踩坑!财报法规检索不准?这款开源工具让答案浮出水面,准确率飙升98.7%!

做 RAG 的人应该都踩过这个致命的坑:把几百页的财报、法规、技术手册扔给向量库,问一个具体问题,搜出来的全是沾边但没用的内容 —— 关键信息要么被硬切块拆碎了,要么藏在几十条结果的最下面。语义相似≠真正相关,这个…

2026/7/28 0:00:29阅读更多 →
抖音视频文案提取工具全指南:免费2026版、手机App、在线工具一网打尽

抖音视频文案提取工具全指南:免费2026版、手机App、在线工具一网打尽

2026年做短视频运营,从抖音上扒文案早就不是偷偷抄笔记的事了。我刚开始做内容的时候,每天刷半小时抖音,手动把爆款视频的口播敲进备忘录,一条2分钟的视频得花十来分钟,碰到语速快的还要反复回听。后来试了一圈工具&am…

2026/7/28 0:00:29阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/28 20:22:24阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/28 3:17:03阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/28 2:35:58阅读更多 →