代码随想录算法训练营Day-37动态规划05 | 完全背包、518. 零钱兑换 II、377. 组合总和 Ⅳ
完全背包视频链接与0-1背包的本质区别0-1背包每个物品最多用1次所以只有0不装包和1装包两种状态完全背包每个物品不限制使用次数。代码上的区别1.容器遍历顺序可正序因为不限制使用次数所以回想一维0-1背包问题在遍历背包时需要倒序是为了避免物品重复选取但完全背包没有这个限制所以倒序改为正序2.先后顺序可颠倒因为0-1背包在遍历背包时要倒序是为了不导致大容量时只能装一个物品不能装多个物品的情况因为遍历大容量时小容量还没遍历所以递推时调用了还没遍历到的元素所以在完全背包这里可以正序从而导致了先后顺序也可以颠倒。先物品后背包的逻辑解释对于当前这个物品i遍历所有容量判断要不要放这个物品i。同时容量的正序遍历导致了小容量时可能已经放入了物品i容量增大 又能放下一个物品i时又放入了一个实现不限制物品使用次数的效果。先背包后物品的逻辑解释对于一个容量j最后一步放哪个物品都可能所以再遍历物品为了找出让价值最大的那个“最后一个物品”。#includeiostream using namespace std; #includevector int main(){ int m,n; cinmn; vectorint weight(m); vectorint value(m); for(int i0;im;i){ cinweight[i]value[i]; } vectorint dp(n1,0); for(int i0;im;i){ for(int jweight[i];jn;j){ dp[j] max(dp[j],dp[j-weight[i]]value[i]); } } coutdp[n]endl; return 0; }518. 零钱兑换 II标准的完全背包求装满有多少种方法的问题。递推公式从最大价值的“dp[j] max(dp[j],dp[j-weight[i]]value[i])”换成了“dp[j]dp[j-coins[i]]”即可其余的标准套路和完全背包一致。解释为什么不需要判别是否装满因为本身dp[j]的含义就是装满容量j的最大装满方法初始化dp[0]1的含义是“要装满容器0只有一种方式什么都不选”。然后从递推公式来看上一时刻dp[j]只会加上j-coins[i]的方式数量比如硬币2容器3的例子j3dp[3]是0只能加上dp[3-2]dp[1];而dp[1]在前面只会加上dp[1-2]但这是不允许的所以根本没有遍历到dp[1]所以dp[3]加了dp[1]也没有还是0所以这种递推逻辑就注定了如果容器填不满根本就不会计数。简单总结dp[j] 只表示“刚好凑满金额 j 的方法数”而 dp[j] dp[j - coins[i]]代表了dp[j]只会从“刚好凑满 j - coins[i]”的方案转移过来每一次转移都是转移的凑满容量的方案数所以最终 dp[amount]就是刚好凑满 amount 的方案数。class Solution { public: int change(int amount, vectorint coins) { vectoruint64_t dp(amount1, 0); dp[0]1; for(int i 0; icoins.size(); i){ for(int j coins[i]; jamount;j){ dp[j]dp[j-coins[i]]; } } return dp[amount]; } };377. 组合总和 Ⅳ本题求的是排列数上一题求的是组合数区别在于求组合数需要使用先物品后背包的顺序求排列数则需要使用先背包后物品的顺序解释递推公式dp[j]dp[j-nums[i]]本质含义是从已有方案最后在加一个硬币先物品后背包物品顺序已经固定如果先遍历物品1后遍历物品2那么只会出现物品1-物品2的顺序不可能出现物品2-物品1的顺序所以只是求的能组合成最后target的组合数顺序不算。先背包后物品每个金额j都枚举“最后一个硬币是谁”不同顺序会被分别统计所以是排列数.举例coins [1, 2]amount 3计算dp[3]先遍历 1dp[3] dp[2] //dp[2]里面有“11”、“2”两种可能所以最终会出现“111”和“21”两个方案再遍历 2dp[3] dp[1] //dp[1]里面有“1”一种可能所以还会再加上“12”一个方案最终共“111”、“21”、“12”三个方案出现了“21”和“12”顺序不同算作不同的方案数。class Solution { public: int combinationSum4(vectorint nums, int target) { vectoruint64_t dp(target1, 0); dp[0]1; for(int j 0; jtarget;j){ for(int i 0; inums.size(); i){ if(jnums[i]) dp[j]dp[j-nums[i]]; } } return dp[target]; } };
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2564013.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!