Day 44 完全背包理论基础 518. 零钱兑换 II 377. 组合总和 Ⅳ

完全背包理论基础

​ 完全背包和0-1背包的最大区别在于完全背包里的每个物品的数量都是无限个,而0-1背包每个物品只有一个;

内嵌循环遍历顺序

​ 回顾一维数组0-1背包的遍历递推公式:

	for (int i = 0; i < weight.size(); i++) {for (int j = bagSize; j >= weight[i]; j--) {dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);}}

​ dp[i][j]是由dp[i - 1][j]以及dp[i - 1][j - weight[i]] + value[i]推导出来的,所有状态都依赖于上一层的状态,

​ 当二维数组压缩为一维数组,失去了i维度的辅助,根据递推公式,此时dp[j]只和左边的以及自己本身有关;

​ 如果正序遍历,由于依赖上一时刻状态,此时前面的数值已经被更新为了当前时刻的状态,后续值会出错;

​ 因此从右向左递推可以保证后面的数据还是基于未被修改的数据计算得到的,因此必须倒序遍历;

​ 所以内嵌循环选择倒序遍历可以确保每个数只添加一次;

​ 而完全背包由于没有这种物品数量的限制,那么完全背包就可以正序遍历:

	for (int i = 0; i < weight.size(); i++) {for (int j = weight[i]; j <= bagSize; j++) {dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);}}

​ 此处完全背包严格意义上来说,对应的递推公式应该是:

	dp[i][j] = max(dp[i - k][j], dp[i][j - k * weight[i]] + k * value[i])//其中,k是取值范围从0到j/weight[i]的整数(闭区间),表示对于第i个物品,在for循环的过程中其实已经实现了取不同k的这个功能

​ dp[j]更新用的值全都是基于本行的左侧的元素进行更新,所以完全背包能也只能正序遍历

​ 如果采用倒序遍历,那么在内层循环中对状态的更新将会影响后续更小容量背包的状态计算,从而导致错误的解。

遍历背包和物品的先后顺序

​ 对于01背包:

​ 二维dp数组的两个for遍历的先后循序是可以颠倒的;

​ 一维dp数组的两个for循环先后循序一定是先遍历物品,再遍历背包容量

​ 对于纯完全背包:

​ 因为dp[j] 是根据下标j之前所对应的dp[j]计算出来的;

​ 只要保证下标j之前的dp[j]都是经过计算的就可以了,颠倒是不会影响结果的;

​ 以下例说明:

​ 背包最大重量为4。

​ 物品为:

重量价值
物品0115
物品1320
物品2430

​ 遍历物品在外层循环,遍历背包容量在内层循环,状态如图:

遍历背包容量在外层循环,遍历物品在内层循环,状态如图:

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

零钱兑换Ⅱ

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

示例 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

示例 2:

  • 输入: amount = 3, coins = [2]
  • 输出: 0
  • 解释: 只用面额2的硬币不能凑成总金额3。

示例 3:

  • 输入: amount = 10, coins = [10]
  • 输出: 1

注意,你可以假设:

  • 0 <= amount (总金额) <= 5000
  • 1 <= coin (硬币面额) <= 5000
  • 硬币种类不超过 500 种
  • 结果符合 32 位符号整数

​ 若将本体视为一个背包问题,则amount就是背包的容量,coins[i]既是weight[i]又是value[i];

​ 由于硬币可以重复选取,既可以视为完全背包问题;

​ 动规五部曲:
​ 1.确定dp数组下标及其含义:
​ dp[j]表示总金额为j时有dp[j]种方式可以凑成;

​ 2.dp数组递推公式:
​ dp[j] += dp[j - coins[i]];

​ 这里的递推公式和494.目标和的递推公式是一样的;

​ 3.初始化:

​ dp[0] = 1;这里的dp[0] = 1严格意义来说是解释不通的,但是由于递推公式的存在,所以只能取dp[0] = 1;

​ 4.遍历顺序:

​ 注意此题要求求的是组合数,下面写出两种遍历方式:

	for (int i = 0; i < coins.size(); i++) {for (int j =0; j <= amount; j++) {//以[1,2]为例//先放coins[0] = 1进去遍历,再放coins[1] = 2进去遍历//所以只会出现集合{1,2},不会出现{2,1}//即此时出现的是组合数}}for (int j = 0; j <= amount; j++) {for (int i =0; i < coins.size(); i++) {//以[1,2,5]为例//遍历背包,则每一个容量下都会遍历所有的元素//即既会出现{1,2},也会出现{2,1}//即此时出现的是排列数}}

​ 5.打印数组:

class Solution {
public:int change(int amount, vector<int>& coins) {vector<int> dp(amount + 1, 0);dp[0] = 1;for (int i = 0; i < coins.size(); i++) { // 遍历物品for (int j = coins[i]; j <= amount; j++) { // 遍历背包dp[j] += dp[j - coins[i]];}}return dp[amount];}
};

组合总和Ⅳ

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

示例:

  • 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)

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

因此输出为 7。

​ 和上题一样的思路,只是这里{1,3}和{3,1}视为两个组合,改变遍历顺序即可;

class Solution {
public:int combinationSum4(vector<int>& nums, int target) {vector<int> dp(target + 1, 0);dp[0] = 1;for(int j = 0; j <= target; j++){for(int i = 0; i < nums.size(); i++){if (j - nums[i] >= 0 && dp[j] < INT_MAX - dp[j - nums[i]]) {//避免相加超过int型dp[j] += dp[j - nums[i]]; }   }}return dp[target];}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/689166.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件工程经济学--期末复习资料

软件工程经济学--期末复习资料 前言第一章 绪论第二章 软件工程经济学基础第三章 软件的成本管理与定价分析第四章 软件工程项目评价方法与经济效果评价第五章 软件生产函数、效益分析及不确定性分析第六章 软件工程项目进度计划的制定结尾总结 前言 软件工程经济学&#xff0…

CSS-伪类选择器

结构伪类选择器 作用&#xff1a;根据元素的结构关系查找元素 分类&#xff1a; 选择器说明元素名:first-child查找第一个元素元素名:last-child查找最后一个元素元素名:nth-child(N)查找第N名元素 <!DOCTYPE html> <html lang"en"> <head><me…

机柜风扇KTS011温湿度控制器KTO011风机控制温控器机械开关温控仪

品牌&#xff1a;威驰 型号&#xff1a;KTS011常开 产地&#xff1a;中国大陆 颜色分类&#xff1a;KTS011常开,KTO011常闭 KTS011与KTO011的区别 KTS011&#xff0c;常开型&#xff0c;可搭配风扇/风机使用&#xff1a;当环境温度超过温控器设定温度&#xff0c;温控…

2024高校网络安全管理运维赛wp

文章目录 misc签到钓鱼邮件识别easyshellSecretDBGatewayzipApachef for r webphpsqlMessy Mongo misc 签到 钓鱼邮件识别 两部分解base64&#xff0c;各一个flag 后面没有什么地方有有用信息了&#xff0c;根据题目钓鱼邮件&#xff0c;可能第三段flag就跟DMARC、DKIM 和 SP…

出海企业哪种组网方案更省事?

对于出海企业而言&#xff0c;建立跨地区的数据传输和协同工作至关重要&#xff0c;以提升运营效率。因此&#xff0c;网络构建变得迫在眉睫。通过构建企业组网&#xff0c;企业能够加强与海外分支、客户和合作伙伴之间的联系&#xff0c;加速海外业务的发展。 然而&#xff0c…

【C语言】—— 动态内存管理

【C语言】——动态内存管理 一、动态内存管理概述1.1、动态内存的概念1.2、动态内存的必要性 二、 m a l l o c malloc malloc 函数2.1、函数介绍2.2、应用举例 三、 c a l l o c calloc calloc 函数四、 f r e e free free 函数4.1、函数介绍4.2、应用举例 五、 r e a l l o …

postgresql中写python去读取HDFS数据,像表一样使用。

简介 首先postgresql是支持python的&#xff0c;在安装postgresql数据库的时候需要执行python支持。可以使用python进行写fundcation 自然也就可以自定义funcation去读取HDFS文件&#xff0c;以此替换掉hive的&#xff0c;省去中间频繁切换服务器的麻烦。 安装postgresql use…

XMind 2021 v11.1.2软件安装教程(附软件下载地址)

软件简介&#xff1a; 软件【下载地址】获取方式见文末。注&#xff1a;推荐使用&#xff0c;更贴合此安装方法&#xff01; XMind 2021 v11.1.2被誉为顶尖思维导图工具&#xff0c;以其简洁、整洁的界面和直观的功能布局脱颖而出。尽管软件体积小巧&#xff0c;却极具强大功…

OpenCV 入门(六) —— Android 下的人脸识别

OpenCV 入门系列&#xff1a; OpenCV 入门&#xff08;一&#xff09;—— OpenCV 基础 OpenCV 入门&#xff08;二&#xff09;—— 车牌定位 OpenCV 入门&#xff08;三&#xff09;—— 车牌筛选 OpenCV 入门&#xff08;四&#xff09;—— 车牌号识别 OpenCV 入门&#xf…

使用in运算符检查状态活动

在具有并行状态分解的Stateflow图表中&#xff0c;子状态可以同时处于活动状态。如果检查状态活动&#xff0c;则可以在两个平行状态下同步子状态。 例如&#xff0c;此图表有两个平行的状态&#xff1a;Place和Tracker。Tracker中的转换会在适当的位置检查状态活动&#xff0c…

icap对flash的在线升级

文章目录 一、icap原语介绍&#xff08;针对 S6 系列的 ICap&#xff09;&#xff0c;之后可以拓展到A7、K7当中去二、程序1设计2.1信号结构框图2.2 icap_delay设计2.3 icap_ctrl设计&#xff08;可以当模板使用&#xff0c;之后修改关键参数即可&#xff09; 三、程序2设计四、…

Edge视频增强功能

edge://flags/#edge-video-super-resolution 搜索Video查找 Microsoft Video Super Resolution 设置为Enabled