跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

动态规划背包问题详解:从入门到实战

动态规划中的背包问题,涵盖 0-1 背包、完全背包及多重背包的核心概念与解法。通过状态定义、转移方程推导及空间优化技巧,结合 C++ 代码示例与经典真题解析,帮助读者掌握资源分配类问题的解题思路,适用于算法面试及工程场景。

KernelLab发布于 2026/3/24更新于 2026/7/2547 浏览
动态规划背包问题详解:从入门到实战

动态规划背包问题详解

一、开篇引言:为什么要学背包问题?

正式讲解前,我们先明确核心问题:为什么要学背包问题?它的价值在哪里?

  • 核心定位:背包问题是动态规划(DP)的经典应用,是理解'状态定义 + 转移方程'的最佳载体。DP 的核心是'拆分复杂问题、复用子问题答案',而背包问题场景直观——'选物品装背包,求最大价值/最优方案',能清晰呈现'子问题重叠'与'状态转移'过程,比其他复杂 DP 问题更易入门。
  • 实际价值:背包问题看似简单,实则对应多种实际需求。算法面试中,大厂常考察其变种题;工程场景里,有限预算的项目分配、有限时间的任务调度,甚至大数据物品推荐,都能用到其核心思想。

二、动态规划基础回顾

背包问题是 DP 的经典应用,我们先快速回顾 DP 核心知识点,避免后续理解断层。

  • 核心思想:将复杂问题拆分为重叠子问题,通过备忘录或 DP 表记录子问题答案,避免重复计算,实现'以空间换时间'。例如,求'前 n 个物品的最大价值',可拆分为'前 n-1 个物品的最大价值'和'第 n 个物品选或不选'的子问题,记录子问题答案即可避免重复计算。

DP 解题四步走(通用框架):这是解决所有 DP 问题的核心模板,背包问题也不例外,务必牢记:

  1. 定义状态:明确 DP 表含义,知道每个位置存储的信息;
  2. 推导转移方程:明确子问题关系,如'选与不选第 i 个物品'的状态变化;
  3. 初始化 DP 表:确定边界条件,如'无物品'或'背包容量为 0'时的状态;
  4. 确定遍历顺序:避免'后序状态影响前序状态',这是背包问题的易错点。
  • 关键提醒:背包问题的核心是'选择'——每个物品只有两种选择:选或不选。所有状态定义、转移方程推导,都围绕'选择后的状态变化'展开,记住这一点就能抓住本质。

三、背包问题核心分类详解(重点)

背包问题有多种分类,核心差异在于'物品选择次数'和'约束条件'。我们重点讲解 3 类基础高频题型(0-1 背包、完全背包、多重背包),再简要拓展其他变种,满足考试基本需求。

3.1 0-1 背包问题(基础中的基础)

0-1 背包是所有背包问题的基础,后续变种均基于其思路推导,务必吃透。

  • 问题定义:n 个物品,每个物品有重量 w[i] 和价值 v[i],背包最大容量为 C,每个物品最多选 1 个('0-1'由来),求装入背包的最大价值。

示例:3 个物品(物品 1:w=2,v=3;物品 2:w=3,v=4;物品 3:w=4,v=5),背包容量 C=5,最大价值为 7(选物品 1 和 2)。

状态定义:先从二维 DP 表入手(易理解),定义 dp[i][j] = 前 i 个物品放入容量 j 的背包,能获得的最大价值。关键点:

  1. '前 i 个物品'指第 1 到 i 个所有物品;
  2. '容量 j'指背包剩余容量,非总容量 C。例如 dp[2][5],即前 2 个物品放入容量 5 的背包的最大价值。

转移方程推导:核心是'选或不选第 i 个物品',取两者最大值:

  1. 不选:dp[i][j] = dp[i-1][j](等同于前 i-1 个物品放入容量 j 的价值);
  2. 选:需留出 w[i] 容量,dp[i][j] = dp[i-1][j - w[i]] + v[i](前 i-1 个物品放入剩余容量的价值 + 当前物品价值)。

综上:j >= w[i] 时,dp[i][j] = max(dp[i-1][j], dp[i-1][j - w[i]] + v[i]); j < w[i] 时,dp[i][j] = dp[i-1][j]。

  • 初始化:核心是边界条件,确保遍历正常进行:① dp[0][j](无物品):无论容量 j 多大,价值均为 0;② dp[i][0](容量为 0):无论物品多少,价值均为 0。例如 dp[0][5] = 0,dp[3][0] = 0。
  • 遍历顺序:必须'先遍历物品,再遍历容量',且容量正序(1 到 C)。若颠倒顺序,会导致同一物品被多次选择(等同于完全背包),违背'最多选 1 个'的规则。
  • 空间优化:二维 DP 空间复杂度为 O(n*C),n 和 C 较大时占用内存多,需优化为一维 DP(滚动数组)。核心:将 dp[i][j] 压缩为 dp[j],表示容量 j 的背包的最大价值,转移方程变为 dp[j] = max(dp[j], dp[j - w[i]] + v[i])。关键细节:容量需倒序遍历(从 C 到 w[i]),避免同一物品重复选择——正序会让 dp[j - w[i]] 包含当前物品选择,倒序则保留前 i-1 个物品的状态。

基础例题:LeetCode 416. 分割等和子集(简化版):给定非空数组,判断能否分割为两个和相等的子集。本质是 0-1 背包:背包容量为数组总和的一半,每个元素为'物品',重量和价值均为元素本身,判断能否装满背包。下面是核心代码:

#include <vector>
#include <algorithm>
using namespace std;

bool f(vector<int>& nums) {
    int total = 0;
    for (int num : nums) total += num;
    if (total % 2 != 0) return false;
    int target = total / 2;
    vector<int> dp(target + 1, 0); // 一维 DP,容量为 target
    for (int num : nums) { // 遍历物品(数组元素)
        for (int j = target; j >= num; j--) { // 倒序遍历容量
            dp[j] = max(dp[j], dp[j - num] + num);
        }
    }
    return dp[target] == target;
}

3.2 完全背包问题(高频考点)

完全背包是 0-1 背包的变种,高频程度不亚于前者,核心差异仅 1 个,抓住即可快速掌握。

  • 问题定义:与 0-1 背包唯一区别——每个物品可无限次选择,其他条件一致(n 个物品、w[i]、v[i]、背包容量 C,求最大价值)。示例同上,完全背包中可重复选物品,但受容量限制,最大价值仍为 7。
  • 核心差异:遍历顺序。0-1 背包倒序遍历容量避免重复选择,完全背包正序遍历容量允许重复选择——正序时,dp[j - w[i]] 已包含当前物品选择,相当于'再次选该物品',符合'无限选'规则。
  • 状态定义与转移方程:沿用一维 DP,dp[j] 表示容量 j 的背包最大价值,转移方程与 0-1 背包一致,仅遍历顺序不同(容量正序)。
  • 空间优化:无需额外优化,一维 DP 即可满足。与 0-1 背包相比,无需刻意避免重复选择,正序遍历即可兼顾空间优化和'无限选'需求。
  • 基础例题:凑硬币(简化版):给定无限枚硬币,求凑成总金额的最大价值(面额即价值)。示例:硬币 [1,2,5],总金额 11,最大价值为 11。核心 C++ 代码(对比 0-1 背包):
#include <vector>
#include <algorithm>
using namespace std;

int maxValue(vector<int>& coins, int amount) {
    vector<int> dp(amount + 1, 0); // 完全背包,硬币可重复选
    for (int coin : coins) { // 遍历物品(硬币)
        for (int j = coin; j <= amount; j++) { // 正序遍历容量(核心区别)
            dp[j] = max(dp[j], dp[j - coin] + coin);
        }
    }
    return dp[amount];
}

3.3 多重背包问题(拓展考点)

多重背包介于 0-1 背包(选 1 次)和完全背包(选无限次)之间,每个物品有有限选择次数,面试频率虽低,但需掌握基础解法和优化思路。

  • 问题定义:每个物品有 k[i] 个,其他条件与 0-1 背包一致(n 个物品、w[i]、v[i]、背包容量 C,求最大价值)。示例:物品 1(w=2,v=3,k=2)、物品 2(w=3,v=4,k=1),背包容量 5,最大价值为 7(选 1 个物品 1 和 1 个物品 2)。
  • 基础解法:转化为 0-1 背包。将 k[i] 个物品拆分为 k[i] 个独立物品(每个仅选 1 次),即可套用 0-1 背包思路。该方法简单,但 k[i] 较大时(如 1000),物品数量剧增,效率低下。
  • 优化解法:二进制拆分法(核心)。将 k[i] 拆分为 2 的幂次之和(如 k=5 拆为 1+2+2,k=7 拆为 1+2+4),每个拆分后的'组合物品'仅选 1 次,可覆盖 0-k[i] 的所有选择情况,将物品数量从 k[i] 缩减至 log2(k[i]),大幅提升效率。
  • 例题:同上示例,二进制拆分后,物品 1 拆为 2 个独立物品,物品 2 拆为 1 个独立物品,转化为 0-1 背包,遍历得最大价值 7。k 较小时差异不明显,k=1000 时,拆分后仅 10 个物品,效率提升显著。

3.4 其他常见背包变种(简要拓展)

除核心 3 类,面试中还会遇到变种,简要讲解核心思路,重点掌握迁移能力,无需深入推导。

  • 二维背包:物品有两个约束(如重量 + 体积),背包有最大重量 C 和体积 V,求最大价值。核心:状态定义扩展为 dp[j][k](容量 j、体积 k 的最大价值),转移方程仍分'选或不选',多一个约束条件。
  • 分组背包:物品分若干组,每组仅选 1 个。核心:遍历顺序调整为'先组、再容量、最后组内物品',转移方程在'选组内物品'和'不选该组'间取最大值。
  • 求方案数/具体方案:在最大价值基础上增加统计逻辑。求方案数可新增 count 数组,记录容量 j 时的最大价值方案数;求具体方案可新增 path 数组,回溯记录选择的物品。

四、背包问题解题技巧与避坑指南

掌握核心分类后,总结解题技巧和常见坑点,帮大家避开误区、提升效率,应对面试更从容。

核心技巧:快速判断背包类型,记住两个维度:

  1. 选择次数:选 1 次(0-1)、无限次(完全)、有限次(多重);
  2. 约束条件:单个(普通)、多个(二维/多维)、分组(分组背包)。定位类型后,直接套用对应思路。

常见坑点:

  1. 遍历顺序错误(最易错):0-1 背包'物品正序、容量倒序',完全背包'物品正序、容量正序',颠倒会导致结果错误;
  2. 初始化错误:忘记初始化 dp[0][j] 或 dp[i][0],导致遍历异常;
  3. 转移方程漏边界:未判断 j >= w[i] 就套用方程,导致数组越界;
  4. 多重背包拆分错误:二进制拆分的幂次和需等于 k[i],否则遗漏选择。

解题模板(通用):

  1. 确定背包类型;
  2. 定义状态(一维/二维);
  3. 推导转移方程;
  4. 初始化 DP 表;
  5. 确定遍历顺序;
  6. 计算结果,必要时回溯方案。新手可直接套用。

调试技巧:出错时,打印 DP 表分析子问题答案。如 0-1 背包打印 dp[j] 变化,重复选择多为遍历顺序错误,结果偏小可能是初始化或转移方程漏边界。

五、实战演练:经典真题解析

理论需结合实战巩固,以下简要解析 3 道 LeetCode 经典真题,对应核心背包类型,帮大家掌握思路转化。

  1. 0-1 背包真题:P1048 采药(经典入门题)。题意:采药时间有限(对应背包容量),每种药材有采集时间(重量)和价值,每种药材只能采一次,求最大可获得价值。

    • 解题思路:直接套用 0-1 背包模板,
      • 状态定义:dp[j] 表示采集时间为 j 时的最大价值;
      • 转移方程:dp[j] = max(dp[j], dp[j - time[i]] + val[i]);
      • 遍历顺序:物品正序、时间倒序;
  2. 完全背包真题:P1616 疯狂的采药(经典拓展题)。题意:与 P1048 采药唯一区别——每种药材可无限次采集(无数量限制),求有限时间内的最大价值。

    • 解题思路:套用完全背包模板,核心差异为遍历顺序(时间正序),
      • 状态定义:dp[j] 含义同 P1048;
      • 转移方程不变,遍历顺序调整为时间正序,允许重复采集;
  3. 多重背包真题:P1776 宝物筛选(经典优化题)。题意:每种宝物有重量、价值和数量限制(k[i] 个),背包有最大容量,求最大价值。

    • 解题思路:采用二进制拆分法优化,将每种宝物的 k[i] 个拆分为 2 的幂次组合,转化为 0-1 背包求解,
      • 拆分逻辑:将 k 拆分为 1、2、4...剩余值,覆盖 0-k 的所有选择;
      • 核心步骤:拆分宝物→遍历拆分后的物品→倒序遍历容量;

解题总结:三道真题精准对应三类核心背包问题,P1048 练 0-1 背包基础,P1616 练完全背包遍历顺序差异,P1776 练多重背包二进制优化,核心均是'套用模板 + 适配题干'。

六、进阶拓展与总结

至此,我们已掌握背包问题核心知识点和实战技巧,下面总结核心要点,并拓展进阶方向,帮大家应对更复杂的面试题。

  • 核心本质:背包问题是'资源分配问题',核心是'选择'与'状态记录'——用有限资源(背包容量),选择最优物品组合,实现收益最大化(或其他目标)。
  • 进阶方向:① 混合背包:多种类型物品结合,分类型处理,套用对应遍历顺序;② 三维背包:三个约束条件,状态定义扩展为三维,思路同二维背包;③ 空间极致优化:针对特定场景(如物品重量大、容量小)优化滚动数组。
  • 学习建议:新手从 0-1 背包入手,先懂二维 DP,再理解空间优化,逐步学习完全、多重背包。多练真题,重点理解'状态定义',而非死记公式,遇到疑问可打印 DP 表分析子问题。
  • 总结:背包问题是 DP 入门钥匙,掌握其思路可迁移到子序列、路径等其他 DP 问题。核心逻辑不难,抓住'拆分问题、记录状态、复用答案',避开坑点,就能轻松应对面试中的背包相关题目。

目录

  1. 动态规划背包问题详解
  2. 一、开篇引言:为什么要学背包问题?
  3. 二、动态规划基础回顾
  4. 三、背包问题核心分类详解(重点)
  5. 3.1 0-1 背包问题(基础中的基础)
  6. 3.2 完全背包问题(高频考点)
  7. 3.3 多重背包问题(拓展考点)
  8. 3.4 其他常见背包变种(简要拓展)
  9. 四、背包问题解题技巧与避坑指南
  10. 五、实战演练:经典真题解析
  11. 六、进阶拓展与总结
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 基于 Cursor 与 Playwright MCP 的 UI 自动化实践
  • WebGIS 实战:WKT 转 GeoJSON 技巧与 Leaflet 集成
  • OpenAI gpt-oss 开源模型本地部署教程
  • 基于 .NET 9 的企业级 Web RBAC 快速开发框架 RuYiAdmin
  • 千笔 AI 辅助论文写作工具功能解析
  • Spring Boot + Leaflet 构建省级旅游口号 WebGIS 可视化平台
  • Visual Studio 使用 GitHub Copilot 与 IntelliCode 辅助编码
  • 高可用集群架构对比与迁移落地指南
  • OpenClaw:开源AI智能体框架的技术架构与部署实践
  • AI 时代产品经理的进化路径与核心能力重构
  • Python 工厂模式封装 Webhook 群聊机器人
  • Python 与前端集成:构建全栈应用
  • AI 编程工具全方位对比:Copilot、Cursor 等主流工具选型指南
  • 算法:长度最小的子数组(滑动窗口解法)
  • RabbitMQ/Spring-AMQP 高级特性:事务机制与消息限流实战
  • 无人机视觉语言导航入门:概念、挑战与应用
  • Java 类的实例化与封装详解
  • 基于 MCP+Skill 的前端 JS 逆向自动化落地实践
  • 分布式系统中如何确保 MQ 消息不丢失、重复消费及积压处理
  • BeyondCompare 安装与试用期重置配置指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online