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:14 阅读更多 →
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:14 阅读更多 →
物联网设备低功耗优化:NBM7100A电源管理方案解析

物联网设备低功耗优化:NBM7100A电源管理方案解析

1. 项目背景与核心挑战在物联网设备设计中,初级电池(不可充电电池)的寿命优化一直是个关键难题。典型的AA/AAA碱性电池在低功耗设备中通常只能维持数月到一年的工作,而许多工业物联网节点需要5年甚至更长的续航能力。这种矛盾催生…

2026/7/28 18:36:14 阅读更多 →

最新新闻

3步轻松备份:GetQzonehistory帮你完整导出QQ空间全部历史说说

3步轻松备份:GetQzonehistory帮你完整导出QQ空间全部历史说说

3步轻松备份:GetQzonehistory帮你完整导出QQ空间全部历史说说 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否曾为QQ空间里那些珍贵的青春回忆无法完整保存而烦恼&…

2026/7/28 18:46:17 阅读更多 →
Ryujinx模拟器终极技术指南:从架构解析到性能优化的完整实现方案

Ryujinx模拟器终极技术指南:从架构解析到性能优化的完整实现方案

Ryujinx模拟器终极技术指南:从架构解析到性能优化的完整实现方案 【免费下载链接】Ryujinx 用 C# 编写的实验性 Nintendo Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/ry/Ryujinx 在PC平台上运行Nintendo Switch游戏面临诸多技术挑战&…

2026/7/28 18:46:17 阅读更多 →
Ubuntu原生安装Dify:生产环境部署与优化指南

Ubuntu原生安装Dify:生产环境部署与优化指南

1. 为什么选择Ubuntu本地安装Dify在技术选型时,我放弃了更简单的Docker方案而选择原生安装,主要基于三个实际考量。首先,生产环境中我们经常需要深度定制AI工作流的底层组件,Docker的隔离性反而会成为调试障碍。上周我就遇到一个案…

2026/7/28 18:46:17 阅读更多 →
如何用GetQzonehistory一键备份你的QQ空间十年记忆?

如何用GetQzonehistory一键备份你的QQ空间十年记忆?

如何用GetQzonehistory一键备份你的QQ空间十年记忆? 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 还在担心那些珍贵的QQ空间说说过几年就找不到了吗?GetQzoneh…

2026/7/28 18:46:17 阅读更多 →
Windows网络测速终极指南:iperf3一键安装与完整使用教程

Windows网络测速终极指南:iperf3一键安装与完整使用教程

Windows网络测速终极指南:iperf3一键安装与完整使用教程 【免费下载链接】iperf3-win-builds iperf3 binaries for Windows. Benchmark your network limits. 项目地址: https://gitcode.com/gh_mirrors/ip/iperf3-win-builds 还在为网络速度不稳定而烦恼吗&…

2026/7/28 18:46:17 阅读更多 →
Plus one (66)

Plus one (66)

Leetcode #66. 算法上没有什么难的,就是要注意细节。栽在坑里了,>9的数忘了清零。 结果搞出[1, 10]这样的list来了。 class Solution:def plusOne(self, digits: List[int]) -> List[int]:if len(digits) 0:return [1]result []carry 0for i in…

2026/7/28 18:45:17 阅读更多 →

日新闻

告别臃肿!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:43 阅读更多 →
RAG必踩坑!财报法规检索不准?这款开源工具让答案浮出水面,准确率飙升98.7%!

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

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

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

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

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

2026/7/28 0:00:43 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/28 12:04:22 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/28 8:29:16 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/28 5:03:42 阅读更多 →

月新闻