完全背包问题

2023-05-16

目录

 一.什么是完全背包

二.完全背包问题的里外层循环可以交换吗

 三.题

3.1 求组合数

3.2 求排列和

3.3 求最小值


 一.什么是完全背包

        完全背包问题一般是指:有N件物品和一个能背重量为W的背包,第i件物品的重量为weight[i],价值为value[i]。每件物品有无限个(也就是可以放入背包多次),求怎样可以使背包物品价值总量最大。

        完全背包与01背包问题的区别在于01背包物品只有一个,完全背包有无数个。

        完全背包问题与01背包问题大致相同,唯一不同的地方体现在遍历顺序方面。

        这里回回顾一下01背包问题的遍历顺序:

        //物品
        for(int i=1;i<=n;i++){
            //背包容量。倒序遍历
            for(int j=V;j>0;j--){
                //放得下
                if(j>=vw[i-1][0]){
                    dp[j]=max(dp[j],dp[j-vw[i-1][0]]+vw[i-1][1]);
                }
                
                //放不下就是原来的值
            }
        }

注意这里是倒序遍历的,如果不倒序遍历回导致一件物品重复选取。

        为什么是重复选取?

        后面的最大价值由前面的值得到,前面得值选取了第i件物品,后面容量仍然可以选取第i件物品,导致第i件物品重复选取。

然而完全背包问题正好一个物品有n件,正好需要重复选取,所以遍历顺序为正序遍历,如下:

        //物品
        for(int i=1;i<=n;i++){
            //背包容量。正序遍历
            for(int j=0;j<=w;j--){
                //放得下
                if(j>=vw[i-1][0]){
                    dp[j]=max(dp[j],dp[j-vw[i-1][0]]+vw[i-1][1]);
                }
                
                //放不下就是原来的值
            }
        }

二.完全背包问题的里外层循环可以交换吗

        看上面的到吗可以看到,01背包问题代码有两层循环,第一层循环为第i个物品,第二层循环是背包的容量。这里有一个问题,这里的遍历顺序可以交换吗?

        首先知道交换里外层遍历顺序意味着什么?意味着,是按物品更新价值,从数组上表现的是,列不变,这一列的每一行价值更新。

        价值更新是由上一行的价值和上一行前面的价值加上现在的价值决定。能不能交换取决于上一行前面的值是否更新。也就是是否可以从里层循环是否可以从前往后遍历。

        01背包对于用二维数组保存结果是可以交换遍历顺序的(前提里层遍历顺序从前往后遍历),用优化的滚动一维数组不可以交换遍历顺序,因为滚动的一维数组里层遍历顺序是从后往前遍历的,价值更新由前面的价值决定,并未更新。

        对于完全背包问题,可以交换。可以从前往后遍历。

 三.题

3.1 求组合数

力扣:518. 零钱兑换 II

给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。

请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。

假设每一种面额的硬币有无限个。 

题目数据保证结果符合 32 位带符号整数。

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

由题意可知,同一硬币可以无限取,首先我们可以发现这是一个组合问题,可以用回溯算法。但是再力扣给的测试用例中会超过时间限制。

由于同一硬币可以无限次取,并且有一目标数,可以使用完全背包开解。

目标数为背包容量,硬币数值代表物品容量,但是这里求的是方法数,并不是求的价值。

状态定义:到达目标值j的方法数,dp[ i ]。

转移方程:这里求的是方法数,并不是求最大价值。

方法数等于:不取这件物品时到达容量j时的方法数(原先的方法数),加上取这件物品到达容量j时的方法数。取这件物品要腾出空间。

        dp[ j ]=dp[ j ]+dp[ j-coins[ i ]]。

初始化:容量为0时不取物品,方法数为1。

返回值:容量为amount时的方法数dp[amount ]。

class Solution {
public:
    int change(int amount, vector<int>& coins) {
        int len=coins.size();
        vector<int> dp(amount+1,0);
        //初始化
        dp[0]=1;

        for(int i=1;i<=len;i++){
            //完全背包,正序遍历
            for(int j=1;j<=amount;j++){
                //求方法数
                if(j>=coins[i-1]){
                     dp[j]+=dp[j-coins[i-1]];
                }
            }
        }
        return dp[amount];

    }
};

3.2 求排列和

力扣:377. 组合总和 Ⅳ

给你一个由 不同 整数组成的数组 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)
请注意,顺序不同的序列被视作不同的组合。

 题目要求 顺序不同被视为不同的组合,实际这是排列问题。

组合不注重顺序,如[ 1,2 ]与[ 2, 1 ]是同一组合

排列注重顺序。如[ 1,2 ]与[ 2, 1 ] 不同排列。

这题与上面这题组成鲜明对比:上面一题是组合问题。

这里有一个结论,本文中提到,完全背包问题的里外层遍历顺序是可以交换的。

注意是有方法数,求价值为总和,总和不变的。

        当求方法数时:

        当外层循环为物品,里层循环为背包容量时,求的是组合数的方法数。

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

        因为当容量够放下第i个物品时,减去的容量coin[ i ]为同一值,不会有其它组合的方法数。

         当外层循环为背包容量,里层循环为物品时,求的是排列数的方法数。

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

 因为当容量可以放下0~j (j<=i) 个物品时,求的方法数,将所有减去coins[ 0 ]~coins[ j ]的值都求进来了。是所有的排列数。

 四个角度我就不分析了,和上面相同,只是遍历顺序变了

class Solution {
public:
    int combinationSum4(vector<int>& nums, int target) {
        int len=nums.size();
        vector<int> dp(target+1,0);
        dp[0]=1;
        //排列问题的完全背包问题
        //这里要改变遍历顺序,外层遍历背包容量,方法上才将排列的所有方法加上
        for(int i=1;i<=target;i++){
            for(int j=1;j<=len;j++){
                //防止dp[i]越界int
                if(i>=nums[j-1]&&dp[i] < INT_MAX - dp[i - nums[j-1]]){
                    dp[i]+=dp[i-nums[j-1]];
                }
            }
        }
        return dp[target];


    }
};

 dp[i] < INT_MAX - dp[i - nums[j-1]]为了防止dp[i]越界int。

3.3 求最小值

力扣 322. 零钱兑换

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

你可以认为每种硬币的数量是无限的。

示例 1:

输入:coins = [1, 2, 5], amount = 11
输出:3 
解释:11 = 5 + 5 + 1

求硬币个数可以无限取 转化为完全背包问题为,背包容量amount,物品容量coins[ i ],价值为1。

状态定义:达到容量i时,硬币数最少为dp[ i ]。

转移方程:这里求的是硬币个数,不管排列还是组合,个数都一样,所以里外层循环求得都一样。

求得硬币数有两种情况

        不取硬币:硬币个数为之前达到容量i时的硬币个数,dp[i]。

        取硬币:硬币个数为先腾出要放的硬币容量,再加1。即 dp[ i-coins[i] ]+1

        最少硬币数为:min(dp[i],dp[ i-coins[i] ]+1)。

初始化:容量为0时,不放硬币数 dp[ 0 ]=0。也可以理解,后面的方法数都时在这个基础上加1。

                容量不为0时,要取一个最大值,因为求的是硬币数的最小值,不初始化为最大值,可能得不到硬币数最小数,而是初始化的值。

        //为什么初始化为INT_MAX,求的是最小值,
        vector<int> dp(amount+1,INT_MAX);
        //为什么初始化为0,每个值都是从容量0开始往上加的
        dp[0]=0;

返回值:值为amount是硬币最少数 dp[ amount ]。

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        int len=coins.size();
        //初始化出0外,其它都初始化为INT_MAX,
        //为什么初始化为INT_MAX,求的是最小值,
        vector<int> dp(amount+1,INT_MAX);
        //为什么初始化为0,每个值都是从容量0开始往上加的
        dp[0]=0;

        for(int i=1;i<=len;i++){
            for(int j=1;j<=amount;j++){
                //防止越界
                if(j>=coins[i-1]&&dp[j-coins[i-1]]<INT_MAX){
                    dp[j]=min(dp[j],dp[j-coins[i-1]]+1);
                    //flag=1;
                
                }
            }
        }
        return dp[amount]==INT_MAX?-1:dp[amount];
        

    }
};

dp[j-coins[i-1]]<INT_MAX)为了防止溢出int。

力扣:279. 完全平方数

给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

给你一个整数 n ,返回和为 n 的完全平方数的 最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。

示例 1:

输入:n = 12
输出:3 
解释:12 = 4 + 4 + 4

 这个题和上面题做法一样,只是要求一个完全平方数的数组。直接上代码

class Solution {
public:
    int numSquares(int n) {
        vector<int> nums;
        int len=sqrt(n);
        //求完全平方数
        for(int i=1;i<=len;i++){
            nums.push_back(i*i);
        }
        
        vector<int> dp(n+1,INT_MAX);
        dp[0]=0;
        for(int i=1;i<=len;i++){
            for(int j=nums[i-1];j<=n;j++){
                if(dp[j-nums[i-1]]<INT_MAX){
                    dp[j]=min(dp[j],dp[j-nums[i-1]]+1);
                }

            }
        }
        return dp[n];

    }
};

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

完全背包问题 的相关文章

  • 一次anaconda+pycharm环境配置出现<No Interpreter>问题的解决办法

    选择add local interpreter后出现如下画面 xff1a 出现如下页面 xff0c 选择安装anaconda目录 xff0c 外面的python exe是base环境的 xff0c 里面envs文件夹中则是自己创建的环境 b
  • Archlinux配置静态的IP地址

    可以参考archwiki中配置网络的部分 使用网络配置工具来配置静态IP地址 dhcpcd可以配置静态的IP地址 xff0c 客户端dhcpcd和服务器端dhcpd是两个不同的软件包 我们使用的时候就是使用客户端的版本 安装dhcpcd s
  • Selenium在定位的class含有空格的复合类的解决办法

    题外话 有个博友看了我的文章之后 xff0c 解决好问题了 xff0c 请点击 xff1a https blog csdn net young gril article details 82754315 其实 xff0c 用CSS属性大法
  • 如何制作多合一Windows镜像

    新人发帖 xff0c 如有错误请纠正 1 准备多个Windows镜像 Vista以上的都可以 和工具包 工具包 zip 蓝奏云 2 随便建个文件夹 xff0c 解压工具包 3 提取Windows镜像中的install wim xff0c 在
  • shell脚本无法执行

    之前我再服务器中直接执行脚本 xff0c 但是无法执行 xff0c 我仔细看了一下原来没有给对应的shell文件设置对应的执行权导致shell无法执行 于是乎我使用了下面的脚本赋予了脚本执行权 chmod 43 x restart sh 这
  • zabbix6.0LTS安装全过程及遇到的问题

    现有centos 7 和mysql8 0 想下载zabbix6 0LTS的 server版本 xff0c 可是发现没有 xff0c 只有proxy 还没搞懂proxy的用处 xff0c 但目前知道不能替代server 所以打算安装cento
  • AndroidStudio使用kotlin入门

    AndroidStudio使用kotlin入门 导读 1 创建第一个kotlin项目2 java代码自动转换成kotlin代码3 开始Hello world ps 由于Markdown在简书里对锚点的支持效果不是很好 xff0c 就没设置跳
  • LAMP架构以及论坛的安装

    LAMP架构 一 熟悉LAMP架构1 Linux平台2 Apache前台3 Mysql后台4 PHP中间连接 二 编译安装Apache httpd服务三 编译安装mysqld服务四 编译安装PHP解析环境五 安装论坛 一 熟悉LAMP架构
  • Android OpenCV基础(一、OpenCV入门)

    一 OpenCV概述 OpenCV xff08 Open Source Computer Vision Library xff09 是一个开源的计算机视觉库 xff0c 它提供了很多函数 xff0c 这些函数非常高效地实现了计算机视觉算法
  • Ubuntu安装最新版本NodeJs和Npm的方法

    第一种方法 通过NodeSource提供的官方包安装 自带最新npm xff08 最推荐 xff09 以下是 Nodejs 18 x的安装 xff0c 一行代码搞定 amp amp 的意思是前面的命令执行无误后 xff0c 再执行后面代码
  • 记录ubuntu 编译android 10 源码遇到的问题

    记录ubuntu 编译android 10 源码遇到的问题 1下载android 10源码 2repo工具下载及安装 xff08 参考网上教程 xff09 3建立源码文件夹 mkdir source cd source 4初始化仓库 我们将
  • @zabbix6.0安装部署(centeros 8 stream)

    文章目录 1 系统版本2 zabbix server官方查看3 平台安装和配置Zabbix服务器4 数据库安装5 Zabbix server配置数据库6 Zabbix前端配置PHP7 zabbix相关组件服务启动8 zabbix web配置
  • 使用Python处理excel表格(openpyxl)教程

    现在有个小任务 xff0c 需要处理excel中的数据 其实就是简单的筛选 xff0c excel玩的不熟练 xff0c 而且需要处理的表有70多个 xff0c 于是想着写个脚本处理一下吧 python中的openpyxl包可以轻松实现读写
  • Linux 6.1/6.2发布新补丁:缓解AMD处理器fTPM间歇性卡顿问题

    导读早些时候 xff0c AMD承认 xff0c 在Linux系统中开启AMD锐龙处理器的fTPM xff0c 将可能导致系统出现间歇性的卡顿 死机等情况 据悉 xff0c 该Bug在Linux 6 1内核中表现得最为明显 xff0c 这是
  • 完美解决主机与虚拟机相互通信,相互ping等问题

    笔者最近在学习使用linux时 xff0c 使用到了vm virtue box的虚拟机服务来简单的安装linux xff0c 但是在使用的时候发现了一个严重的问题 xff1a 虚拟机可以ping通主机 xff0c 主机却无法ping通虚拟机
  • CSS——CSS的选择器

    概念 xff1a CSS在渲染 HTML 页面是 xff0c 为了得到 HTML 中的标签进行样式渲染 xff0c 为我们提供了大量好用的各种选择器 xff0c 以便于我们在CSS 中拿到 HTML 的标签进行样式设置 一 基本选择器 基本
  • OA工作流的浅谈

    如今 xff0c 越来越多的人意识到将工作流引入解决方案的重要性 随着信息技术的发展和商业竞争的日益激烈 xff0c 人们不再满足于独立 分散的办公自动化和计算机应用 xff0c 而需要全面 集成的解决方案 作为一种管理和集成常规事务的技术
  • GPG key retrieval failed: [Errno 14] curl#60 - “Peer‘s Certificate has expired.“

    GPG key retrieval failed Errno 14 curl 60 Peer s Certificate has expired GPG key retrieval failed Errno 14 curl 60 Peer
  • html,css常见的几种垂直居中方式

    一丶什么是垂直居中 指当前标签在父级容器中垂直方向是居中显示的 实现垂直居中的几种方式 xff1a 1 table cell 43 vertical align 属性配合使用 2 absolute 43 transform 属性配合使用 3
  • STM32用XCOM调试助手打印不出数据

    STM32用XCOM调试助手打印不出数据 被困扰了一段时间的串口终于解决了 xff0c 用STM332F103ZET6写串口 xff0c 但是不懂为什么打开串口调试助手就是打印不出数据 首先检查了代码有没有错 xff0c 因为是按照网上的代

随机推荐

  • 基于蚁群算法的机器人路径规划matlab——代码注释超级详细,都能看懂

    采用蚁群算法路径规划matlab 本文对基本蚁群算法代码进行了详细的注释 每一步都简单易懂 程序在matlab中可直接运行 适合刚开始学习本算法的同学入门 蚁群算法是由意大利学者Dorigo提出的一种仿生智能算法 最早运用在旅行商问题上 蚁
  • java集合类(collection)

    一 集合类 collection Java中有哪些容器 xff08 集合类 xff09 Java中的集合类主要由Collection和Map这两个接口派生而出 xff0c 其中Collection接口又派生出三个子接口 xff0c 分别是S
  • linux安装程序和软件

    文章目录 一 解析Linux应用软件安装包二 rpm命令2 1 安装有依赖关系的 rpm软件包 xff0c 2 2 升级或更新 rpm软件包2 3 实列2 4 查询未安装的 rpm软件包文件 一 解析Linux应用软件安装包 通常Linux
  • Postman入门教程【没有废话,直入实战,绝对给力!】

    基础篇 Postman功能 xff08 https www getpostman com features xff09 主要用于模拟网络请求包快速创建请求回放 管理请求快速设置网络代理安装 下载地址 xff1a https www getp
  • U3D开发的逆天级大型游戏有哪些

    1 World of Diving 潜水世界 一款潜水游戏 潜水世界 xff1a http dx60 downyouxi com qianshuishijie zip 氛围不错 xff0c 不过细看建模好像不是特别精细的样子 2 The F
  • 线程安全(实现线程方式+线程状态+通信方式,sleep,wait,守护线程)

    目录 用户自定义线程 Java中实现多线程的方法 xff1a 如何停止一个正在运行的线程 1 说说什么是线程安全 xff1f 如何实现线程安全 xff1f 2 Java中线程的状态有哪些 xff1f 线程间的通信方式有哪些 xff1f 追问
  • LINUX——远程访问控制ssh

    文章目录 一 什么是SSH xff1f 二 SSH远程管理 服务端2 1 SSH协议2 2服务监听选项2 3用户登录控制 Authentication xff1a 2 4登录验证方式 三 TCP Wrappers控制3 1 2保护机制的实现
  • 关于Visual studio 2010运行时闪退问题的解决

    在运行一个刚刚下载的visual studio 2010时候 xff0c 编程一个简单程序进行输出时候 xff0c 会出现闪退状况 明明成功编译了 xff0c 但是没有显示结果 xff0c 只是闪了一下就自己关闭了 解决方法1 在main函
  • GFF/GTF简介及格式转换

    最近做转录组的比对时 xff0c 在建立索引过程中 xff0c 遇见一个问题 xff0c 就是我从ncbi下载的序列文件和gtf文件中 xff0c 染色体命名规则竟然不一样 xff0c 但序列文件和gff文件染色体命名规则是一样的 xff0
  • Linux 系统上安装R及加载R包

    因为安装Hic Pro xff0c 需要依赖几个R包 xff0c 比如ggplot2 又依赖 gt 4 0的R xff0c 之前安的3 6 xff0c 再重新安装一遍最新的吧 xff0c 记录一下 xff0c 省去了以后再重复查资料的过程
  • BWA比对及Samtools提取目标序列

    今天想看一下自己的序列里面会不会有某细菌基因组存在 xff0c 主要使用BWA和Samtools xff1a bwa主要用于将低差异度的短序列与参考基因组进行比对 主要包含三种比对算法 xff1a backtrack SW和MEM xff0
  • 核糖体rRNA分类-功能应用-数据库-Silva

    一 xff0e 分类 xff1a 原核生物的rRNA分三类 xff1a 5SrRNA 16SrRNA和23SrRNA 真核生物的rRNA分四类 xff1a 5SrRNA 5 8SrRNA 18SrRNA和28SrRNA S为大分子物质在超速
  • RepeatMasker基因组重复序列检测工具安装及使用

    一 RepeatMasker简介 基因组组装完成后 xff0c 进行基因预测和注释 由于基因组中存在重复序列结构区 xff0c 特别是高等真核生物 xff0c 重复序列占了相当大的比例 xff0c 会影响基因预测的质量 xff0c 也会带来
  • Seqkit:强大的序列处理工具

    Seqkit是一款专门处理fsata q序列文件的软件 github地址 https github com shenwei356 seqkit 下载地址 xff1a https bioinf shenwei me seqkit downlo
  • Minimap2:三代比对工具

    在使用Purge dups去冗余时 xff0c 用到了Minimaps2 xff0c 把学习的东西整理一下 先声明本文软件介绍的很多内容来自 生信算法 公众号文章 xff0c 用来作为自己的学习记录 xff0c 原文作者若不同意的话就删稿
  • 白盒测试:语句覆盖、条件覆盖、判定覆盖、条件-判定覆盖、组合覆盖、路径覆盖

    语句覆盖 xff1a 所有的 语句 都要覆盖一遍 判定覆盖 xff1a 包含语句覆盖 xff0c 每个判断T F各一次 条件覆盖 xff1a 包含语句覆盖 xff0c 每个条件T F各一次 判定条件覆盖 xff1a 包含判定覆盖 条件覆盖
  • GMAP一款比对工具用于ALLHiC构建等位基因表

    在ALLHiC使用过程中需要构建Allele ctg table xff0c 用于过滤多倍体基因组中因等位序列相似引起的HiC噪音的必要输入 官网提供了两种办法 xff0c 一种是blastn xff0c 需要对草图基因组进行注释 xff0
  • 数据结构——平衡二叉树(AVL树)之插入

    文章目录 前言一 定义二 基本操作1 查找 xff0c 2 插入 如何调整 如何调整代码实现插入 前言 首先我们来思考一下一个普通二叉树保存数据 xff0c 如果想查找一个数据 xff0c 由于普通二叉树保存数据是随机的 xff0c 要找到
  • C++之引用怎么用

    1 引用的概念 引用并不是新定义一个变量 xff0c 而是给一个已存在的变量取一个别名 编译器并不会为引用变量开辟空间 xff0c 它和它应用的变量共用一块空间 也就是说引用是同一块变量空间的不同名字 格式 xff1a 类型 amp 引用变
  • 完全背包问题

    目录 一 什么是完全背包 二 完全背包问题的里外层循环可以交换吗 三 题 3 1 求组合数 3 2 求排列和 3 3 求最小值 一 什么是完全背包 完全背包问题一般是指 xff1a 有N件物品和一个能背重量为W的背包 xff0c 第i件物品