news 2026/8/10 22:56:57

动态规划解决选数求和问题:洛谷P15800题解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
动态规划解决选数求和问题:洛谷P15800题解

1. 项目概述:洛谷P15800动态规划题目解析

这道来自洛谷平台的P15800题目,是GESP2026年3月六级认证的真题,考察的核心算法思想是动态规划在组合数学问题中的应用。题目要求从给定的n个正整数中选取若干个数,使得它们的和等于给定的目标值m,计算所有可能的选取方案数。

在实际编程竞赛和算法面试中,这类"选数求和"问题是动态规划的经典应用场景。与简单的暴力枚举相比,动态规划能够将时间复杂度从O(2^n)优化到O(n*m),这在n和m较大时(比如n=100,m=10000)能带来数百万倍的性能提升。

2. 动态规划基础与问题分析

2.1 动态规划的核心思想

动态规划(Dynamic Programming)通过将原问题分解为相对简单的子问题的方式来求解复杂问题。它有三个关键特征:

  1. 最优子结构:问题的最优解包含子问题的最优解
  2. 重叠子问题:递归算法会反复计算相同的子问题
  3. 无后效性:当前状态一旦确定,后续决策不受之前决策影响

对于选数问题,我们可以定义dp[i][j]表示考虑前i个数时,和为j的方案数。这个状态定义满足上述三个特征,因此适合用动态规划解决。

2.2 问题输入输出分析

题目典型输入格式:

n m a1 a2 ... an

其中:

  • n:数字个数 (1 ≤ n ≤ 100)
  • m:目标和 (1 ≤ m ≤ 10000)
  • ai:每个数字的值 (1 ≤ ai ≤ 1000)

输出为一个整数,表示选取方案数。

例如: 输入:

4 5 1 2 3 4

输出:

2

解释:有两种方案可以得到和5 (1+4 和 2+3)

3. 动态规划解法详解

3.1 状态转移方程推导

我们定义dp[i][j]为考虑前i个数时,和为j的方案数。状态转移需要考虑两种情况:

  1. 不选第i个数:方案数等于dp[i-1][j]
  2. 选第i个数:方案数等于dp[i-1][j-ai](前提是j ≥ ai)

因此,状态转移方程为:

dp[i][j] = dp[i-1][j] + (j >= ai ? dp[i-1][j-ai] : 0)

初始条件:

  • dp[0][0] = 1 (0个数和为0有1种方案)
  • dp[0][j] = 0 for j > 0 (0个数和大于0没有方案)

3.2 空间优化技巧

观察状态转移方程可以发现,dp[i]只依赖于dp[i-1],因此可以将二维数组优化为一维数组,节省空间:

vector<int> dp(m+1, 0); dp[0] = 1; for(int i = 1; i <= n; i++) { for(int j = m; j >= a[i]; j--) { dp[j] += dp[j - a[i]]; } }

注意内层循环需要从大到小遍历,避免重复计算(这是背包类问题的常见技巧)。

4. 完整代码实现与解析

4.1 C++实现代码

#include <iostream> #include <vector> using namespace std; int main() { int n, m; cin >> n >> m; vector<int> a(n+1); for(int i = 1; i <= n; i++) { cin >> a[i]; } vector<int> dp(m+1, 0); dp[0] = 1; for(int i = 1; i <= n; i++) { for(int j = m; j >= a[i]; j--) { dp[j] += dp[j - a[i]]; } } cout << dp[m] << endl; return 0; }

4.2 代码关键点解析

  1. 输入处理:使用vector存储数字,从索引1开始更符合问题描述
  2. 初始化:dp数组大小为m+1,初始化dp[0]=1
  3. 双重循环:外层遍历数字,内层逆向遍历和
  4. 状态转移:dp[j] += dp[j-a[i]]实现状态转移
  5. 输出:最终dp[m]即为答案

5. 算法优化与变种讨论

5.1 时间与空间复杂度分析

  • 时间复杂度:O(n*m),两重循环
  • 空间复杂度:O(m),使用一维数组优化

5.2 常见变种问题

  1. 每个数字只能选一次(本题情况)
  2. 每个数字可以选无限次(完全背包问题)
  3. 需要输出具体方案而不仅是方案数
  4. 数字包含负数的情况
  5. 求最接近m的和(不一定要等于m)

对于变种3(输出具体方案),可以在动态规划后通过回溯法找出所有方案:

void backtrack(int i, int j, vector<int>& path) { if(j == 0) { // 输出方案 for(int num : path) cout << num << " "; cout << endl; return; } if(i == 0 || j < 0) return; // 不选a[i] backtrack(i-1, j, path); // 选a[i] if(j >= a[i] && dp[i-1][j-a[i]] > 0) { path.push_back(a[i]); backtrack(i-1, j-a[i], path); path.pop_back(); } }

6. 实战技巧与注意事项

6.1 常见错误与调试技巧

  1. 数组越界:确保dp数组大小足够(m+1)
  2. 初始化错误:忘记初始化dp[0]=1
  3. 循环顺序错误:内层循环必须逆向遍历
  4. 整数溢出:方案数可能很大,考虑使用long long

调试技巧:可以打印中间dp表,观察状态转移是否正确

6.2 性能优化建议

  1. 输入优化:对于大规模数据,使用快速输入方法
    ios::sync_with_stdio(false); cin.tie(0);
  2. 提前终止:如果某个dp[j]已经不可能达到,可以跳过
  3. 空间优化:如前述使用一维数组

6.3 测试用例设计

设计测试用例时应考虑:

  1. 边界情况:n=1,m=1
  2. 无解情况:所有数字都大于m
  3. 大数情况:测试整数溢出
  4. 重复数字:数组中有重复数字
  5. 极端数据:n=100,m=10000

示例测试用例:

// 样例1 3 5 1 2 3 // 应输出:2 // 样例2 4 6 1 2 3 4 // 应输出:3 (1+2+3, 2+4, 1+5) // 样例3 5 10 2 4 6 8 10 // 应输出:3 (2+8, 4+6, 10)

7. 动态规划学习路径建议

对于想系统学习动态规划的选手,建议按照以下顺序进阶:

  1. 基础背包问题:

    • 01背包(本题类型)
    • 完全背包
    • 多重背包
  2. 线性动态规划:

    • 最长上升子序列(LIS)
    • 最长公共子序列(LCS)
    • 最大子数组和
  3. 区间动态规划:

    • 矩阵链乘法
    • 石子合并
    • 最优二叉搜索树
  4. 树形动态规划:

    • 树的最大独立集
    • 树的直径
    • 树上背包问题
  5. 状态压缩动态规划:

    • 旅行商问题(TSP)
    • 棋盘覆盖问题

对于GESP六级考生,重点掌握前两类即可应对大多数考题。洛谷题库中有大量分类练习题,建议从"普及-"难度的动态规划题目开始刷起。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/10 22:56:08

Python投资组合分析:从数据到决策的量化投资实战指南

Python投资组合分析&#xff1a;从数据到决策的量化投资实战指南 【免费下载链接】pyfolio Portfolio and risk analytics in Python 项目地址: https://gitcode.com/gh_mirrors/py/pyfolio 在量化投资领域&#xff0c;如何从海量金融数据中提取有价值的洞察&#xff0c…

作者头像 李华
网站建设 2026/8/10 22:52:19

工业模拟测量与控制技术详解:06 ADC:模拟世界进入数字世界

第六章 ADC:模拟世界进入数字世界 ——从连续物理量到工业控制数据 本章目标 工业自动化系统最终处理的是数字数据。但工业现场真实存在的是温度、压力、流量、液位、振动、电流、电压等连续变化的物理量。 因此,工业控制系统必须解决一个最基础的问题: 如何把连续变化的…

作者头像 李华
网站建设 2026/8/10 22:48:29

RPCS3:在PC上完美运行PS3游戏的终极开源方案

RPCS3&#xff1a;在PC上完美运行PS3游戏的终极开源方案 【免费下载链接】rpcs3 PlayStation 3 emulator and debugger 项目地址: https://gitcode.com/GitHub_Trending/rp/rpcs3 RPCS3是全球首个免费开源的PlayStation 3模拟器和调试器&#xff0c;让玩家能够在Windows…

作者头像 李华
网站建设 2026/8/10 22:48:23

律所财税优化怎么做?靠谱服务商选择指南

律所财税管理&#xff0c;从来不是简单的记账报税。合伙制的利润分配、律师个税的累进税率、项目制的成本分摊&#xff0c;每一项都暗藏风险。2026年&#xff0c;随着税务监管趋严&#xff0c;律所财税优化已从“可选项”变为“必答题”。然而&#xff0c;市面上的财税服务商鱼…

作者头像 李华
网站建设 2026/8/10 22:44:11

3步搞定!让老款Mac运行最新macOS的终极指南

3步搞定&#xff01;让老款Mac运行最新macOS的终极指南 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 你是否有一台性能依然强劲却被苹果官方"抛弃&quo…

作者头像 李华