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


    问题

    注:大佬对此类问题的解法:动态规划背包问题总结
    给你一个由 不同 整数组成的数组 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 <= nums[i] <= 1000
    nums 中的所有元素 互不相同
    1 <= target <= 1000

    程序

    #include 
    
    // 定义一个函数来计算总和为目标整数的元素组合的个数
    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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    解释

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

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

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

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

    假设数组 nums 为 [1, 2, 3],目标值 target 为 4。
    初始时,dp 数组如下:

    dp[0] = 1
    dp[1] = 0
    dp[2] = 0
    dp[3] = 0
    dp[4] = 0
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    开始计算 dp[1]:

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

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

  • 相关阅读:
    小程序商城运营如何做好用户定位和用户需求
    利用Flutter的特性最大程度提升iOS应用的用户体验
    Spring+SpringMVC+MyBatis框架整合的配置
    [MyBatisPlus]DQL编程控制②(查询投影、查询条件)
    Ansible playbook中 block用法
    4月2日-3日·上海 | 3DCC 第二届3D细胞培养与类器官研发峰会携手CGT Asia 重磅来袭
    Flink 数据交换策略 Partitioner
    Java字符串常用操作
    【lc】678-有效括号模式
    【Spring Boot】常用参数与注解
  • 原文地址:https://blog.csdn.net/weixin_47139576/article/details/133818790