OI Wiki 背包 DP:如何选择背包类型并完成状态转移

发布时间:2026/9/15 21:18:38

OI Wiki 背包 DP:如何选择背包类型并完成状态转移 OI Wiki 背包 DP如何选择背包类型并完成状态转移【免费下载链接】OI-wiki:star2: Wiki of OI / ICPC for everyone. 某大型游戏线上攻略内含炫酷算术魔法项目地址: https://gitcode.com/GitHub_Trending/oi/OI-wiki在 OI WikiMkDocs 构建的 OI / ICPC 知识 Wiki中背包 DP 是 动态规划部分的核心模型之一面对一道选物求最大价值的问题你需要先判断物品「能被选几次」再套对应的转移写法。这篇文章沿着 背包 DP 一篇给出可落地的路径按选次约束选择 0-1、完全、多重或混合背包写出空间压缩后的状态转移再用仓库自带的例题代码和样例输入输出验证你的实现。按物品的选取次数选择背包类型文档中四种模型的差别只在于每种物品可以被选几次据此对号入座背包类型文档给出的选取约束转移枚举方向一维压缩后0-1 背包每个物品只能取一次容量从大到小l从W枚举到w[i]完全背包每种物品可以选取无限次容量从小到大l从w[i]枚举到W多重背包每种物品有 $k_i$ 个而非一个容量从大到小内层再枚举选取数量 $k$混合背包有的只能取一次、有的取无限次、有的取 $k$ 次逐物品判断后分别套用上面的核心代码判断依据来自题目对选取次数的描述文档以 「USACO07 DEC」Charm Bracelet 为例说明 0-1 背包——每个物体只有取与不取两种状态完全背包「与 0-1 背包的区别仅在于一个物品可以选取无限次而非仅能选取一次」多重背包「与 0-1 背包的区别在于每种物品有 $k_i$ 个而非一个」混合背包则是「将前面三种的背包问题混合起来」。0-1 背包状态定义与反向转移设状态 $f_{i,j}$ 为只能放前 $i$ 个物品时容量为 $j$ 的背包能达到的最大总价值转移方程为$$ f_{i,j}\max(f_{i-1,j},f_{i-1,j-w_{i}}v_{i}) $$文档指出二维记录会 MLE由于对 $f_i$ 有影响的只有 $f_{i-1}$可去掉第一维得到一维方程 $f_j\max(f_j,f_{j-w_i}v_i)$。关键在枚举顺序。下面这段是文档标注的错误核心代码for (int i 1; i n; i) for (int l 0; l W - w[i]; l) f[l w[i]] max(f[l] v[i], f[l w[i]]);它错在$j\geqslant w_i$ 时 $f_{i,j}$ 会被同一轮的 $f_{i,j-w_i}$ 影响相当于物品 $i$ 被多次放入——文档特别说明这正是完全背包的解法。修正方法是容量从 $W$ 枚举到 $w_i$保证 $f_{i,j}$ 总是在 $f_{i,j-w_i}$ 之前被更新for (int i 1; i n; i) for (int l W; l w[i]; l--) f[l] max(f[l], f[l - w[i]] v[i]);完全背包同样的转移正向枚举完全背包的状态定义与 0-1 相同但转移方程不同。朴素做法是枚举第 $i$ 件物品选了多少个时间复杂度 $O(n^3)$$$ f_{i,j}\max_{k0}^{\infty}(f_{i-1,j-k\times w_i}v_i\times k) $$优化后只需通过 $f_{i,j-w_i}$ 转移因为 $f_{i,j-w_i}$ 已经充分考虑了第 $i$ 件物品的选取次数$$ f_{i,j}\max(f_{i-1,j},f_{i,j-w_i}v_i) $$去掉第一维后压缩的循环恰好是正向的——也就是上一节里对 0-1 背包而言错误、对完全背包而言正确的写法。多重背包先转成 0-1再用二进制分组多重背包可以直接枚举每种物品选 $k_i$ 次把「每种物品选 $k_i$ 次」等价转换为「有 $k_i$ 个相同的物品各选一次」时间复杂度 $O(W\sum_{i1}^nk_i)$核心代码for (int i 1; i n; i) { for (int weight W; weight w[i]; weight--) { // 多遍历一层物品数量 for (int k 1; k * w[i] weight k cnt[i]; k) { dp[weight] max(dp[weight], dp[weight - k * w[i]] k * v[i]); } } }$O(\sum k_i)$ 部分可用二进制分组优化把第 $i$ 种物品拆成由 $2^j$ 个单个物品「捆绑」而成的大物品若 $k_i1$ 不是 $2$ 的整数次幂最后补一个剩余数量捆绑的大物品。文档给出的拆分示例$6123$$81241$$1812483$$31124816$拆分后按 0-1 背包求解时间复杂度降为 $O(W\sum_{i1}^n\log_2k_i)$。仓库中的分组代码变量 $p$、$h$、$k$ 分别为单价重量、单价价值和数量index 0; for (int i 1; i m; i) { int c 1, p, h, k; cin p h k; while (k c) { k - c; list[index].w c * p; list[index].v c * h; c * 2; } list[index].w p * k; list[index].v h * k; }若需进一步优化文档指向 单调队列/单调栈优化。混合背包逐物品判断后套用对应核心代码混合背包的伪代码引自文档就是逐物品分派for (循环物品种类) { if (是 0 - 1 背包) 套用 0 - 1 背包代码; else if (是完全背包) 套用完全背包代码; else if (是多重背包) 套用多重背包代码; }以 「Luogu P1833」樱花 为例核心代码用cnt[i]是否为零区分两种路径for (int i 1; i n; i) { if (cnt[i] 0) { // 如果数量没有限制使用完全背包的核心代码 for (int weight w[i]; weight W; weight) { dp[weight] max(dp[weight], dp[weight - w[i]] v[i]); } } else { // 物品有限使用多重背包的核心代码它也可以处理0-1背包问题 for (int weight W; weight w[i]; weight--) { for (int k 1; k * w[i] weight k cnt[i]; k) { dp[weight] max(dp[weight], dp[weight - k * w[i]] k * v[i]); } } } }注释里还给了一个实用结论多重背包的核心代码同样能处理 0-1 背包数量上限为 1 时内层循环自然只跑一次所以只需「无限 / 有限」两分支即可覆盖三种模型。编译例题代码并用样例输入验证仓库提供了两份可直接编译的例题程序和配套样例。注意两份程序的输入顺序不同这是代码实际读入的顺序决定的knapsack_1.cpp0-1 背包先读n Wknapsack_2.cpp完全背包先读W n。0-1 背包例题读入n W随后 $n$ 行每行w[i] v[i]g -O2 -o knapsack_1 docs/dp/code/knapsack/knapsack_1.cpp ./knapsack_1 docs/dp/examples/knapsack/knapsack_1.in样例输入knapsack_1.in为4 6加四行物品1 4、2 6、3 12、2 7文档配套的标准答案文件 knapsack_1.ans 内容是一个数23。你自己的程序对该样例输出 23即与文档样例一致。完全背包例题读入W n随后 $n$ 行每行w[i] v[i]g -O2 -o knapsack_2 docs/dp/code/knapsack/knapsack_2.cpp ./knapsack_2 docs/dp/examples/knapsack/knapsack_2.in样例输入knapsack_2.in为70 3加三行物品71 100、69 1、1 2knapsack_2.ans 内容为140。此外仓库把例题代码的编译与正确性作为贡献检查的一环scripts/README.md 说明存在测试文档实例代码正常编译的脚本CLAUDE.md 给出在本地环境Python 3.10、uv、Yarn 就绪下运行python3 scripts/correctness_check.py对 C 示例做编译验证的方式适合批量改动例题代码后自查。边界与注意事项枚举顺序是两类模型的分水岭0-1 背包正向枚举会退化成完全背包物品可多次放入完全背包反向枚举则只选一次。改代码时先确认目标模型再定l的增减方向。输出方案类问题需要额外记录用 $g_{i,v}$ 标记第 $i$ 件物品占用空间 $v$ 时是否被选转移时记录采用「选 / 不选」哪种策略再从最后一件物品倒推详见 背包 DP 的「输出方案」小节求方案数则把转移中的 $\max$ 换成求和、初始条件设为 $dp_01$求最优方案总数需把状态改为「正好装满」并对 $f$ 数组按负无穷0xcf初始化、$f[0]0$、$g[0]1$。二维费用背包如 「Luogu P1855」榨取 kkksc03在状态中增加一维存放第二种费用即可但文档提醒不要再为物品编号开一维容易 MLE分组背包同组最多选一个对每组做一次 0-1 背包文档特别强调「一定不能搞错循环顺序」。文档的参考资料一节列出了崔添翼的《背包问题九讲》作为延伸阅读。完成上面任一路径后可以打开 背包 DP 核对对应小节的转移方程与核心代码是否一致遇到单调队列优化或多叉树依赖背包等进一步话题再分别进入 单调队列/单调栈优化 或 动态规划部分简介 继续。【免费下载链接】OI-wiki:star2: Wiki of OI / ICPC for everyone. 某大型游戏线上攻略内含炫酷算术魔法项目地址: https://gitcode.com/GitHub_Trending/oi/OI-wiki创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/15 21:13:38

高危端口排查与加固指南:从SSH暴力破解到Redis未授权访问

做安全运维这些年,每次拿到一台新服务器的第一件事就是扫一遍端口。说实话,看到 22、3389、3306、6379 这类端口直接裸奔在公网上的服务器,我都会替对方捏把汗。高危端口不是危言耸听,而是无数攻击事件用惨痛教训换来的共识。这篇…

2026/9/15 21:13:38

极验四代滑块验证码轨迹构造:物理模型与行为特征模拟实战

说实话,极验四代滑块验证码这玩意儿,我在很长一段时间里看见就头疼。前两篇我们聊了怎么定位缺口、怎么拿参数,但那都只是前戏。真正决定你能不能稳定跑通的,就是标题里写的这三个字:轨迹构造。你就算把缺口识别得再准…

2026/9/15 21:58:42

抖音音乐批量下载指南:主页作品原声一键提取

抖音音乐批量下载指南:主页作品原声一键提取 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback support. 抖音批…

2026/9/15 21:58:42

告别命令行:nTopology可视化建模快速生成Voronoi泡沫

上周帮朋友调整一个鞋底中底的轻量化结构,他想做的东西很明确:三维Voronoi泡沫——一堆随机的胞元互相连通,看起来像海绵,踩上去又要能回弹。我原本打算用老路子,命令行加减Python脚本去跑scipy.spatial.Voronoi&#…

2026/9/15 4:54:30

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/15 0:01:16

AI英语单词APP开发:自适应学习算法与移动端优化实践

1. 项目概述 作为一名在移动应用开发领域摸爬滚打多年的老手,我最近完成了一个AI英语单词APP的开发项目。这个项目将传统单词记忆方法与现代AI技术相结合,打造了一款能够智能适应不同用户学习习惯的英语学习工具。 市面上大多数单词APP都存在一个通病&a…

2026/9/15 0:01:16

Flutter与OpenHarmony结合开发手语学习APP实战

1. 项目背景与核心价值作为一名同时接触过Flutter和OpenHarmony的开发者,最近我完成了一个基于Flutter for OpenHarmony的手语学习APP实战项目。这个项目最大的特点在于实现了跨平台框架与国产操作系统深度结合的创新实践——用Flutter开发的应用能完美运行在OpenHa…

2026/9/15 0:01:16

六个月成为机器人工程师:从ROS2到SLAM的实战路径

1. 六个月的紧迫感从哪来:先搞清楚你要成为哪种机器人工程师说实话,六个月的期限并不是一个宽松的时间线。市面上任何一本正经的机器人学教材都超过五百页,ROS2的官方文档可以翻到你怀疑人生,再加上ABB、KUKA这些工业机器人厂家动…

2026/9/15 14:22:53

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/15 21:31:11

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/15 11:42:23

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码