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];
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

线程知识点

一、线程 1.定义 线程&#xff1a;是一个进程并发执行多种任务的机制。 串行&#xff1a;多个任务有序执行&#xff0c;一个任务执行完毕后&#xff0c;再去执行下一个任务 并发&#xff1a;多个任务在单个CPU上运行&#xff0c;同一个时间片上只能运行一个任务&#xff0c;c…

漫谈AI时代的手机

以chatGPT 为代表的大语言的横空出世使人们感受到AI 时代的到来&#xff0c;大语言模型技术的最大特点是机器开始”懂人话“&#xff0c;”说人话“了。如同任何一个革命性工具的出现一样&#xff0c;它必将改变人类生活和工作。 在这里。我谈谈AI时代的手机。 语音通信的历史…

如何将Hyper-V转VMware?反之亦可

为何要在Hyper-V和VMware之间进行转换呢&#xff1f; 尽管VMware和Microsoft Hyper-V都是当前流行的一类虚拟机监控程序&#xff0c;但它们并不相互兼容。VMware产品使用VMDK格式创建虚拟磁盘&#xff0c;而Hyper-V则使用VHD或VHDX格式创建虚拟磁盘。 有时您可能需要进行这种转…

找不到msvcp120dll,无法继续执行代码的多种解决方法分享

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp120.dll丢失”。这个错误通常会导致某些应用程序无法正常运行。为了解决这个问题&#xff0c;我们需要采取一些措施来修复丢失的msvcp120.dll文件。本文将介绍6种常见的解决方法&…

cubic 相比 bbr 并非很糟糕

迷信 bbr 的人是被它的大吞吐所迷惑&#xff0c;我也不想再解释&#xff0c;但我得反过来说一下 cubic 并非那么糟。 想搞大吞吐的&#xff0c;看看我这个 pixie 算法&#xff1a;https://github.com/marywangran/pixie&#xff0c;就着它的思路改就是了。 cubic 属于 aimd-ba…

c++ STL 之栈—— stack 详解

vector 是 stl 的一个关联容器,名叫“栈”&#xff0c;何为“栈”&#xff1f;其实就是一个数组&#xff0c;但有了数组何必还需栈&#xff0c;这是一个高深的问题。 一、简介 1. 定义 栈&#xff0c;是一个柔性数组&#xff08;可变长数组&#xff09;&#xff0c;可以变大变小…

【qt】纯代码界面设计

界面设计目录 一.界面设计的三种方式1.使用界面设计器2.纯代码界面设计3.混合界面设计 二.纯代码进行界面设计1.代码界面设计的总思路2.创建项目3.设计草图4.添加组件指针5.初始化组件指针6.添加组件到窗口①水平布局②垂直布局③细节点 7.定义槽函数8.初始化信号槽9.实现槽函数…

最新!TOP200高校!5月ESI排名,公布!

【SciencePub学术】5月9日&#xff0c;ESI数据库更新了2024年5月最新ESI数据。据统计&#xff0c;全球共有9019家科研机构上榜&#xff0c;其中有449所中国内地高校。 ESI&#xff08;基本科学指标数据库&#xff09;是目前世界范围内普遍用以评价高校、学术机构、国家或地区国…

JavaScript 动态网页实例 —— 事件处理应用

前言 事件处理的应用很广泛。在事件处理的应用中,鼠标事件的应用是最常用到的。本章给出几个鼠标事件处理应用的示例,包括:页面预览、图像切换、点亮文本、鼠标跟随、鼠标感应和禁用鼠标按键。在这些示例中,有的可以直接拿来应用,有的则只提供了一种应用的方法,稍加拓展,…

深入解析RedisSearch:全文搜索的新维度

码到三十五 &#xff1a; 个人主页 在当今的数据时代&#xff0c;信息的检索与快速定位变得尤为关键。Redis&#xff0c;作为一个高性能的内存数据库&#xff0c;已经在缓存和消息系统中占据了重要地位。然而&#xff0c;Redis并不直接支持复杂的搜索功能。为了填补这一空白&am…

QT7_视频知识点笔记_3_自定义控件,事件处理器⭐,定时器,QPainter,绘图设备,不规则窗口

第三天&#xff1a; 自定义控件&#xff0c;事件处理器⭐&#xff0c;定时器&#xff0c;QPainter,绘图设备&#xff0c;不规则窗口实现 1.自定义控件&#xff1a; 创建新的QT控件类&#xff0c;然后再需要使用的地方--》提升为 来使用如何使用基础控件的信号和槽函数&…

Flutter-Statewidget 创建State过程State<XXXX> createState() => _XXXXState()的解释

文章目录 创建widget 的状态对象示例代码解析 完整的代码示例总结 创建widget 的状态对象 今天有个同学问了我下State createState() > _XXXXState()时什么意思。这个代码在flutter开发中一直看到&#xff0c;很多人都不关心这个&#xff0c;直接当模板使用。今天来介绍下这…

Python中tkinter编程入门3

在使用tkinter创建了窗口之后&#xff0c;可以将一些控件“放置”到窗口中。这些控件包括标签、按键以及输入框等。 1 在窗口中“放置”标签 在窗口中“放置”标签主要有两个步骤&#xff0c;一是创建标签控件&#xff0c;二是将创建好的标签“放置”到窗口上。 1.1 创建标签…

Maven- Profile详解

前言 Profile能让你为一个特殊的环境自定义一个特殊的构建&#xff1b;profile使得不同环境间构建的可移植性成为可能。 <project><profiles><profile><build><defaultGoal>...</defaultGoal><finalName>...</finalName><…

通过自建镜像方式搭建RabbitMQ集群

通过自建镜像方式搭建RabbitMQ集群 1. 应用准备1.1 应用目录结构1.2 配置文件1.2.1 .erlang.cookie1.2.2 hosts1.2.3 rabbitmq.conf1.2.4 rabbitmq-env.conf 2. 编写DockerFile2.1 将所有本地文件拷贝到工作目录2.2 拷贝文件到源目录&增加执行权限2.3 安装Erlang & rab…

WAAP全站防护理念,发现和保护敏感数据

数据是现代企业的新石油&#xff1a;正确使用它可以促进公司的发展并帮助企业在竞争中领先。就像石油一样&#xff0c;原始数据和未被发现的数据是毫无用处的&#xff0c;企业将无法从中受益&#xff1b;在最坏的情况下&#xff0c;它可能会导致安全事件。这也是企业投资敏感数…

Python | Leetcode Python题解之第75题颜色分类

题目&#xff1a; 题解&#xff1a; class Solution:def sortColors(self, nums: List[int]) -> None:n len(nums)p0, p2 0, n - 1i 0while i < p2:while i < p2 and nums[i] 2:nums[i], nums[p2] nums[p2], nums[i]p2 - 1if nums[i] 0:nums[i], nums[p0] num…

R语言数据探索与分析-碳排放分析预测

# 安装和加载需要的包 install.packages("readxl") install.packages("forecast") install.packages("ggplot2") library(readxl) library(forecast) library(ggplot2)# 数据加载和预处理 data <- read_excel("全年数据.xlsx") co…

全新神经网络架构KAN——本文用于学习与探索

论文地址&#xff1a;https://arxiv.org/pdf/2404.19756 Github&#xff1a;GitHub - KindXiaoming/pykan: Kolmogorov Arnold Networks 文档说明&#xff1a;Welcome to Kolmogorov Arnold Network (KAN) documentation! — Kolmogorov Arnold Network documentation 本文仅…

A计算机上的程序与B计算机上部署的vmware上的虚拟机的程序通讯 如何配置?

环境&#xff1a; 在A计算机上运行着Debian11.3 Linux操作系统&#xff1b;在B计算机上运行着Windows10操作系统&#xff0c;并且安装了VMware软件&#xff0c;然后在VMware上创建了虚拟机C并安装了CentOS 6操作系统 需求&#xff1a; 现在A计算机上的程序需要同虚拟机C上的软…