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

动态规划解决背包问题与分割等和子集

使用动态规划解决背包问题(携带研究材料)和分割等和子集(LeetCode 416)的方法。涵盖二维和一维 DP 数组的推导过程,提供 C++ 代码实现,并分析了时间与空间复杂度。重点在于状态转移方程的构建及滚动数组的空间优化技巧。

颠三倒四发布于 2026/3/28更新于 2026/10/2290 浏览

背包问题(携带研究材料)

解题思路:动态规划(二维)

首先读取物品数量 m 和背包容量 n,再分别读取 m 个物品的重量数组 weight 和价值数组 value,接着初始化一个 m * (n + 1) 的二维 dp 数组,dp[i][j] 表示前 i + 1 个物品放入容量为 j 的背包能获得的最大价值,并初始化第一行当背包容量 j 大于等于第一个物品重量时,dp[0][j] 赋值为第一个物品的价值,然后通过双层循环遍历剩余物品和所有容量,若当前容量 j 小于第 i 个物品重量,则无法放入该物品,dp[i][j] 等于上一行同列的值,即不选该物品的最大价值,否则取不选该物品 dp[i - 1][j] 和选该物品 dp[i - 1][j - weight[i]] + value[i] 中的较大值更新 dp[i][j],最终输出 dp[m - 1][n],即所有物品放入容量为 n 的背包能获得的最大价值。

具体代码

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

int main() {
    int m;
    int n;
    cin >> m >> n;
    vector<int> weight(m, 0);
    vector<int> value(m, 0);
    for (int i = 0; i < m; i++) cin >> weight[i];
    for (int i = 0; i < m; i++) cin >> value[i];
    vector<vector<int>> dp(m, vector<int>(n + 1, 0));
    for (int i = weight[0]; i <= n; i++) dp[0][i] = value[0];
    for (int i = 1; i < m; i++) {
         ( j = ; j <= n; j++) {
             (j < weight[i]) dp[i][j] = dp[i - ][j];
             dp[i][j] = (dp[i - ][j], dp[i - ][j - weight[i]] + value[i]);
        }
    }
    cout << dp[m - ][n];
     ;
}
for
int
0
if
1
else
max
1
1
1
return
0

时间复杂度:O(m * n) 空间复杂度:O(m * n)

解题思路:动态规划(一维)

首先读取物品数量 m 和背包容量 n,再分别读取 m 个物品的重量数组 weight 和价值数组 value,接着初始化一个长度为 n + 1 的一维 dp 数组,dp[j] 表示容量为 j 的背包能装下的最大价值,初始值全为 0,然后通过双层循环遍历物品和背包容量,外层循环逐个遍历 m 个物品,内层循环从后往前遍历背包容量从 n 到当前物品重量 weight[i],这样能避免重复选取同一物品,对于每个容量 j,取不选当前物品保持 dp[j] 原值和选当前物品 dp[j - weight[i]] + value[i],即容量 j - weight[i] 的最大价值加上当前物品价值中的较大值更新 dp[j],最终输出 dp[n],即容量为 n 的背包能获得的最大价值。

具体代码

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

int main() {
    int m;
    int n;
    cin >> m >> n;
    vector<int> weight(m, 0);
    vector<int> value(m, 0);
    for (int i = 0; i < m; i++) cin >> weight[i];
    for (int i = 0; i < m; i++) cin >> value[i];
    vector<int> dp(n + 1, 0);
    for (int i = 0; i < m; i++) {
        for (int j = n; j >= weight[i]; j--) {
            dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
        }
    }
    cout << dp[n];
    return 0;
}

时间复杂度:O(m * n) 空间复杂度:O(n)

分割等和子集(LeetCode 416)

解题思路:动态规划(二维)

首先计算数组所有元素的总和,若总和为奇数则直接返回 false,无法分割为两个和相等的子集,若为偶数则将目标值 target 设为总和的一半,即需找到子集和为 target,接着初始化一个二维 dp 数组 dp[i][j] 表示前 i + 1 个元素中选取若干个,能组成的不超过 j 的最大和,并初始化第一行,当 j 大于等于第一个元素值时,dp[0][j] 赋值为该元素值,然后通过双层循环遍历剩余元素和所有可能的和,若当前 j 小于第 i 个元素值,则无法选取该元素,dp[i][j] 等于上一行同列值,否则取不选该元素 dp[i - 1][j] 和选该元素 dp[i - 1][j - nums[i]] + nums[i] 的较大值更新 dp[i][j],过程中若发现 dp[i][j] 等于 target 则提前返回 true,若遍历结束未找到则返回 false。

具体代码

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = 0;
        for(int i = 0; i < nums.size(); i++) sum += nums[i];
        if(sum % 2) return false;
        int target = sum / 2;
        vector<vector<int>> dp(nums.size(), vector<int>(target + 1, 0));
        for (int j = 0; j <= target; j++)
            if (j >= nums[0]) dp[0][j] = nums[0];
        for (int i = 1; i < nums.size(); i++) {
            for (int j = 1; j <= target; j++) {
                if (j < nums[i]) dp[i][j] = dp[i - 1][j];
                else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - nums[i]] + nums[i]);
                if (dp[i][j] == target) return true;
            }
        }
        return false;
    }
};

时间复杂度:O(n * target) 空间复杂度:O(n * target)

解题思路:动态规划(一维)

首先计算数组所有元素的总和,若总和为奇数则直接返回 false,无法分割为两个和相等的子集,若为偶数则将目标值 target 设为总和的一半,即需找到子集和为 target,接着初始化长度为 target + 1 的一维 dp 数组 dp[j] 表示选取若干元素能组成的不超过 j 的最大和,初始值全为 0,然后通过双层循环遍历数组元素和目标和,外层逐个遍历数组元素,内层从后往前遍历 target 到当前元素值避免重复选取同一元素,对每个 j 取不选当前元素保持 dp[j] 原值和选当前元素 dp[j - nums[i]] + nums[i] 的较大值更新 dp[j],过程中若发现 dp[target] 等于 target 则提前返回 true,若遍历结束未满足条件则返回 false。

具体代码

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = 0;
        for (int i = 0; i < nums.size(); i++) sum += nums[i];
        if (sum % 2) return false;
        int target = sum / 2;
        vector<int> dp(target + 1, 0);
        for (int i = 0; i < nums.size(); i++) {
            for (int j = target; j >= nums[i]; j--) {
                dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
                if (dp[target] == target) return true;
            }
        }
        return false;
    }
};

时间复杂度:O(n * target) 空间复杂度:O(target)

目录

  1. 背包问题(携带研究材料)
  2. 解题思路:动态规划(二维)
  3. 具体代码
  4. 解题思路:动态规划(一维)
  5. 具体代码
  6. 分割等和子集(LeetCode 416)
  7. 解题思路:动态规划(二维)
  8. 具体代码
  9. 解题思路:动态规划(一维)
  10. 具体代码

更多推荐文章

查看全部
  • Arduino BLDC 无刷电机模糊逻辑避障控制实战
  • Dify MCP-Server 插件:将工作流发布为第三方可调用服务
  • 突破 LLM 上下文瓶颈:上下文内存虚拟化 CMV 的设计与实践
  • MySQL 安装指南:Ubuntu 环境下快速部署与配置
  • AI 数据标注平台选型实践与效率提升技术逻辑
  • 基于 Django 的 4S 店客户管理系统设计与实现
  • Android 性能优化实战指南:核心原理与面试应对策略
  • 英文论文 AI 率检测:IThenticate 与 Turnitin 系统对比
  • 二分答案专题实战:木材加工与砍树问题解析
  • Python Selenium 模拟登录实战与自动化技巧
  • Llama-Factory 大模型微调实战指南
  • GitHub Copilot 学生开发者包申请与激活指南
  • 程序员必会的 50 种算法(第 2 版):从基础到 LLM 实战
  • 企业级 Web 大学生一体化服务平台管理系统:SpringBoot+Vue+MyBatis 架构
  • LangChain4j 集成多模型 Provider 方案:OpenAI 与本地模型混合部署
  • 算法题解:740.删除并获得点数
  • 无人机避障:Mid360+Fast-lio 感知建图+Ego-planner 运动规划
  • AI 核心概念解析:Skill、MCP 与 Function Call
  • 快速排序:划分方法、优化与非递归实现
  • 大模型训练原理:从自监督学习到 GPT 架构解析

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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