动态规划 -背包问题-详解

问题

注:大佬对此类问题的解法:动态规划背包问题总结

给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。

题目数据保证答案符合 32 位整数范围。

示例 1:

输入:nums = 1,2,3, target = 4

输出:7

解释:

所有可能的组合为:

(1, 1, 1, 1)

(1, 1, 2)

(1, 2, 1)

(1, 3)

(2, 1, 1)

(2, 2)

(3, 1)

请注意,顺序不同的序列被视作不同的组合。

示例 2:

输入:nums = 9, target = 3

输出:0

提示:

1 <= nums.length <= 200

1 <= numsi <= 1000

nums 中的所有元素 互不相同

1 <= target <= 1000

程序

c 复制代码
#include <stdio.h>

// 定义一个函数来计算总和为目标整数的元素组合的个数
int combinationSum4(int* nums, int numsSize, int target) {
    // 创建一个动态规划数组 dp,长度为 target + 1
    int dp[target + 1];
    
    // 初始化 dp 数组,将所有元素初始化为0
    for (int i = 0; i <= target; i++) {
        dp[i] = 0;
    }

    // 初始状态:总和为0时,只有一种组合方式,即什么都不选
    dp[0] = 1;

    // 开始填充 dp 数组
    for (int i = 1; i <= target; i++) {
        for (int j = 0; j < numsSize; j++) {
            // 如果当前的目标总和减去数组元素可达
            if (i - nums[j] >= 0) {
                // 则将 dp[i] 增加 dp[i - nums[j]],表示加上当前元素后的组合数
                dp[i] += dp[i - nums[j]];
            }
        }
    }

    // 返回 dp 数组中最终目标总和的组合数
    return dp[target];
}

int main() {
    int nums[] = {1, 2, 3};
    int target = 4;
    int numsSize = sizeof(nums) / sizeof(nums[0]);

    // 调用 combinationSum4 函数,计算组合数
    int result = combinationSum4(nums, numsSize, target);

    // 打印结果
    printf("输出:%d\n", result);

    return 0;
}

解释

在动态规划中,dpi - nums\[j] 表示以目标值 i 减去数组中的某个元素 numsj 后的状态。这通常用于动态规划问题中,特别是在处理组合问题时,来记录前一步的状态。

在上述程序中,dpi 表示总和为 i 的组合数。当计算 dpi 时,我们遍历数组 nums 中的元素,对于每个元素 numsj,我们考虑将其加入总和为 i 的组合中。为了计算 dpi,我们需要考虑两种情况:

  1. 如果 i 大于等于 numsj,那么我们可以将 numsj 加入到总和为 i 的组合中。此时,我们需要考虑的是将 numsj 加入后,剩余的总和为 i - numsj 的组合数,这就是 dpi - nums\[j]。
  2. 如果 i 小于 numsj,则 numsj 不能被加入到总和为 i 的组合中,因为它会导致总和超过
    i。因此,在这种情况下,dpi - nums\[j] 为0。

所以,dpi - nums\[j] 表示以目标值 i 减去数组中的某个元素 numsj 后的状态,即剩余的部分。通过考虑所有可能的 numsj,我们可以累加所有这些情况,以计算总和为 i 的组合数 dpi。这就是动态规划的思想:将较大问题分解成较小问题,并使用较小问题的解来构建较大问题的解。

假设数组 nums 为 1, 2, 3,目标值 target 为 4。

初始时,dp 数组如下:

c 复制代码
dp[0] = 1
dp[1] = 0
dp[2] = 0
dp[3] = 0
dp[4] = 0

开始计算 dp1:

  • i 等于 1,numsj 等于 1,因此 i >= numsj。
  • 我们考虑将 1 加入到总和为 1 的组合中,剩余的总和是 1 - 1 = 0。
  • 此时,dp0 为1,因为只有一种组合方式,即什么都不选。
  • 所以,dp1 = dp1 - 1 = dp0 = 1。
    继续计算 dp2 和 dp3:
  • dp2 的计算和 dp1 类似,因为我们可以将 2 加入到总和为 2 的组合中,dp2 = dp2 - 2 = dp0 = 1。
  • dp3 的计算也类似,因为我们可以将 3 加入到总和为 3 的组合中,dp3 = dp3 - 3 = dp0 = 1。
    最后,计算 dp4:
  • 对于 dp4,我们可以考虑将 1 加入到总和为 4 的组合中,这就是 dp4 - 1 = dp3 = 1。
  • 我们还可以考虑将 2 加入到总和为 4 的组合中,这就是 dp4 - 2 = dp2 = 1。
  • 同样,我们可以考虑将 3 加入到总和为 4 的组合中,这就是 dp4 - 3 = dp1 = 1。
  • 然后,将这些情况的组合数累加起来,即 dp4 = 1 + 1 + 1 = 3。

最终,dp4 的值为 3,表示总和为 4 的组合数为 3 种,即 1, 1, 1, 1、1, 1, 2 和 2, 2。

相关推荐
倒头就睡的小比特3 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼3 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
旖旎夜光3 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark3 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her13 天前
并查集-听课笔记
笔记·算法·并查集
码流子3 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven3 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark3 天前
从算法设计模式看编程思维的抽象能力4
算法
2601_962218613 天前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法