day46--动态规划6

文章探讨了完全背包问题的两种变体:零钱兑换(求组合数)和组合总和(求排列数),介绍了动态规划的五步法,包括dp数组定义、递推公式、初始化和遍历顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  •  完全背包
  •  518. 零钱兑换 II 
  •  377. 组合总和 Ⅳ  

第一题:完全背包

有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和最大。

完全背包和01背包问题唯一不同的地方就是,每种物品有无限件

跟01背包的实现区别在哪里?

答:

for(int j = 0; j <= bagWeight; j++) { // 遍历背包容量
        for(int i = 0; i < weight.size(); i++) { // 遍历物品
            if (j - weight[i] >= 0) dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
        }
    }

物品是从小到大遍历,装到装不了然后再从小的开始。

第二题: 零钱兑换 II 

给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。

示例 1:

  • 输入: amount = 5, coins = [1, 2, 5]
  • 输出: 4

解释: 有四种方式可以凑成总金额:

  • 5=5
  • 5=2+2+1
  • 5=2+1+1+1
  • 5=1+1+1+1+1

钱币数量不限,说明是完全背包。不过本题要实现的目标是凑成总金额的组合个数。

(1)确定dp数组以及下标的含义

dp[j]:凑成总金额的货币组合数为dp[j]

(2)确定递推公式

dp[j]就是所有dp[j-weight[i]]的相加

dp[j]+=dp[j-coins[i]]; 金币j上的组合数等于没加这个金币之前的所有组合数之和

(3)dp数组如何初始化

dp[0]=1  0容量也是一种容量。

(4)确定遍历顺序

本题求的是组合数,不考虑排列的问题,所以应该是先遍历物品,再遍历容量

        for (int i = 0; i < coins.size(); i++) { // 遍历物品
            for (int j = coins[i]; j <= amount; j++) { // 遍历背包
                dp[j] += dp[j - coins[i]];
            }
        }

(5)举例推导dp数组

先遍历物品,再遍历背包,也就是先横着遍历,再往第二层遍历。

第三题:组合总和Ⅳ

给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数

示例:

  • nums = [1, 2, 3]
  • target = 4

所有可能的组合为: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1)

本题还是求组合的个数,类似前面的可重复的硬币,但是硬币是组合问题,本题是排列问题。

动态规划五部曲

(1)确定dp数组及其下标含义

dp[i]:凑成目标正整数i的排列个数。

(2)确定递推公式:

如同硬币题,dp[i]+=dp[i-nums[j]]; 

dp[i](考虑nums[j])可以由 dp[i - nums[j]](不考虑nums[j]) 推导出来。

因为只要得到nums[j],排列个数dp[i - nums[j]],就是dp[i]的一部分。

(3)dp数组如何初始化

这种递推公式的前提下,大部分dp[0]=1

(4)确定遍历顺序

如果求组合数就是外层for循环遍历物品,内层for循环遍历背包;

如果求排列数就是外层for循环遍历背包,内层for循环遍历物品。

(5)举例推导数组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值