当前位置: 首页 > news >正文

【算法设计与分析】第7篇:01背包问题的动态规划建模与空间优化

给定一个容量有限的背包和若干件物品,每件物品有各自的重量和价值,每件物品只能选择装入或不装入,问在总重量不超过背包容量的前提下,能获得的最大价值。这就是经典的01背包问题,其名称来源于每件物品的“要么0要么1”的二元选择。

这个问题的暴力枚举需要O(2ⁿ)时间,而动态规划将它压缩到O(nW),其中n为物品数量,W为背包容量。这个跨度,足以说明动态规划在处理组合优化时的威力。


一、二维动态规划建模

状态定义。令dp[i][j]表示从前i件物品中选取若干件,放入容量为j的背包中能获得的最大价值。这里i是物品索引的“考虑范围”,j是背包的“剩余容量”,两者共同构成状态空间的坐标。

最优子结构。考察第i件物品。它只有两种选择:不装入,则问题退化为前i-1件物品在容量j下的最优解dp[i-1][j];装入,则需要在前i-1件物品、容量j-w[i]的基础上增加价值v[i]。只要j≥w[i],我们就在两者之间取较大值。这给出了状态转移方程:

dp[i][j]={dp[i−1][j],j<w[i]max⁡{ dp[i−1][j],dp[i−1][j−w[i]]+v[i] },j≥w[i]dp[i][j]=⎩⎨⎧​dp[i−1][j],max{dp[i−1][j],dp[i−1][j−w[i]]+v[i]},​j<w[i]j≥w[i]​

初始化。dp[0][j]全为0——没有物品可选时,无论背包多大,价值都是零。dp[i][0]全为0——容量为零,装不下任何东西。

填表顺序。外层循环枚举i从1到n,内层循环枚举j从0到W,按行逐格填充。最终答案位于dp[n][W]。时间复杂度Θ(nW),空间复杂度Θ(nW)。


二、滚动数组:从二维到一维的空间优化

观察上面的递推式可以发现一个关键性质:dp[i][j]的值只依赖于上一行dp[i-1]中的两个位置——正上方的dp[i-1][j]和左前方的dp[i-1][j-w[i]]。一旦第i行计算完成,第i-1行就再也不会被用到。

这意味着我们不需要保留整个二维表。只需一个长度为W+1的一维数组,并在每一轮物品迭代中“就地”更新它。但这里有一个容易被忽视的细节——内层循环的方向。

如果j从小到大遍历,那么dp[j-w[i]]在当前这一轮中可能已经被更新过了,代表的是dp[i][j-w[i]]而非我们需要的dp[i-1][j-w[i]],这相当于允许同一件物品被重复使用(变成完全背包)。要避免这一点,j必须从W向w[i]递减遍历,确保dp[j-w[i]]读取到的是上一轮残留的值。

优化后的代码结构异常简洁:一维数组f初始全零,外层遍历物品,内层j从W递减到w[i],执行f[j]=max(f[j], f[j-w[i]]+v[i])。空间复杂度从Θ(nW)降至Θ(W)。


三、背包问题的变形族

01背包是背包家族的基准模型,许多变体只需在转移方程上稍作调整。

完全背包:每件物品可以选无限次。只需将内层j的遍历方向改为从小到大,使同一物品可被反复选取。dp[j] = max(dp[j], dp[j-w[i]]+v[i]),j递增。

多重背包:每件物品有固定的数量上限s[i]。朴素方法是将s[i]个相同物品拆开当成01背包处理,但这样效率低下。更优的做法是二进制拆分:将s[i]分解为1,2,4,...,2ᵏ,剩余数这些“打包”后的新物品,每种最多选一次,转化为01背包求解。更高阶的优化是使用单调队列进行线性处理,但那已经属于进阶专题的范畴。

分组背包:物品被划分为若干组,每组内至多选一件。这需要在01背包的外层增加一个组枚举层,内层对组内物品做决策,循环顺序与01背包类似但需注意j循环在组内物品循环的外面,以保证每组只选一件。


四、为什么“容量”是多项式却不算多项式时间算法

一个值得思考的理论细节:背包问题的动态规划复杂度是O(nW),n是物品数量,W是背包容量。看起来是多项式,但若W以输入中的二进制位数计,W的数值本身就是输入规模的指数。因此背包问题的DP解法实际是伪多项式时间算法,这一问题在NP完全性的讨论中将被再次提及。

从矩阵链乘法到01背包,我们看到的动态规划都是在一个有限的表格中按规则递推。下一篇,我们将面对更具挑战性的字符串场景——最长公共子序列与编辑距离,在那里状态将横跨两个序列,二维表格上的转移方向也会更为丰富。

http://www.jsqmd.com/news/887018/

相关文章:

  • Lovable后端集成故障恢复SLA达标率从63%→99.99%:我们重构了3层适配器、替换2个SDK、自研1个协议转换网关(含SLO监控看板截图)
  • Claude本地化部署终极方案(企业级容器化全栈手册):支持Anthropic API兼容、流式响应、模型热切换与RBAC权限隔离
  • Veo 2提示词工程进阶手册(导演级Prompt拆解):98%用户忽略的镜头语法、时空锚点与情绪动词结构
  • 123546
  • 2026年上海离婚诉讼律师TOP5盘点:上海遗产分割律师/上海遗产处理律师/上海遗产律师/上海遗产继承律师/上海遗嘱律师/选择指南 - 优质品牌商家
  • 基于CD4093与拍频效应的无MCU LED呼吸灯硬件实现
  • 你不是在舒适区,你在漂移
  • AI驱动的数据分类分级:工程化架构设计与落地实践详解
  • 鸿蒙非遗博览页面构建:技艺展示与分类导航模块详解
  • 粒子不聚焦?散焦过度?3类高频粒子失焦问题诊断树(含CLI日志解析指令+--debug输出解读速查表)
  • 国家软考中级·信息系统管理工程师:全网最硬核备考拆解
  • Sentry框架:GPU原生ML工件认证,零开销保障模型与数据完整性
  • 2026公路波形护栏技术拆解与核心供应商参考:波形梁钢护栏板/省道波形护栏/路侧护栏板/道路波形护栏/镀锌波形护栏/选择指南 - 优质品牌商家
  • 建站系统深度拆解:从“搭积木”到内容管理,一文读懂底层逻辑
  • 【大白话说Java面试题 第74题】【Mysql篇】第4题:InnoDB 和 MyISAM 的数据文件存储区别?
  • ComfyUI-WD14-Tagger:AI图像标签自动提取工具完全指南
  • 2026年哪家公司可以做GEO获客和AI搜索排名提升?九颐数科给出完整判断路径 - 观域传媒
  • 树莓派+OpenHAB打造低成本eBUS网关:自制转换器实现锅炉智能监控
  • DeepSeek安全测试辅助与Burp Suite Pro联调失败?4个隐藏权限配置错误正在吞噬你的漏洞覆盖率
  • 【大白话说Java面试题 第75题】【Mysql篇】第5题:MySQL 的聚簇索引和非聚簇索引的区别是什么?
  • 3步解锁专业级MMD创作:Blender插件如何重塑二次元动画工作流
  • QMCDecode终极指南:3步解锁QQ音乐加密格式,实现跨平台音乐自由
  • 洞察2026年近期贵阳高中复读班市场:机构竞争格局与选型指南 - 2026年企业推荐榜
  • 从SaaS到自建CMS的选型复盘:一个专注网站开发的技术选型笔记
  • 从Mesa到Wayland:图解libdrm在Linux图形栈里的‘粘合剂’角色
  • 从Chrome 122到ChromeDriver 122:版本匹配背后的自动化测试‘玄学’与最佳实践
  • 智慧树自动刷课助手:3步告别手动操作的学习效率工具
  • 【复现】中国上市公司全要素生产率测算与分析(论文+数据)
  • DeepSeek+DDD融合架构设计:从Prompt边界建模到智能体领域事件流编排(独家方法论首发)
  • 保姆级避坑指南:在Ubuntu 22.04上用ROS2 Humble搞定TurtleBot3的SLAM与导航(附常见报错解决方案)