DAY47:动态规划(九)完全背包理论基础

news2024/11/19 5:26:44

文章目录

    • 完全背包示例
    • 与01背包的区别:遍历顺序
      • 常规遍历写法
      • DP状态图-为什么背包正序就能放进来重复物品
    • for循环的嵌套,外层物品内层背包能否颠倒?
      • for嵌套顺序颠倒的遍历写法
    • 测试示例
    • 面试题目
    • 总结

课程链接: 代码随想录 (programmercarl.com)

完全背包示例

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

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

同样leetcode上没有纯完全背包问题,都是需要完全背包的各种应用,需要转化成完全背包问题,我们通过纯完全背包问题理解原理。

题目示例:

背包最大重量为4。

物品为:

在这里插入图片描述
每件商品都有无限个!

问背包能背的物品最大价值是多少?

与01背包的区别:遍历顺序

完全背包在写法上,与01背包唯一区别就是遍历顺序。

常规遍历写法

01背包遍历顺序:

for(int i=0;i<weight.size();i++){//物品在外
    for(int j=bagWeight;j>=weight[i];j--){//背包在内,且背包倒序
        dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
    }  
}

遍历顺序和倒序相关问题:DAY45:动态规划(六)背包问题优化:一维DP解决01背包问题_大磕学家ZYX的博客-CSDN博客

01背包内嵌的背包容量循环倒序遍历为了保证每个物品仅被添加一次

而完全背包的物品是可以添加多次的,所以要从小到大去遍历,即:

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

DP状态图-为什么背包正序就能放进来重复物品

可以通过DP状态图看一下原因。如下图,可以解释为什么背包容量正序遍历,就会放进来很多重复的物品。图中可知,如果正序,同一物品的情况下,就会累加dp[j[-weight[i]]],导致这个物品i被放进去很多次

在这里插入图片描述

for循环的嵌套,外层物品内层背包能否颠倒?

其实还有一个很重要的问题,为什么遍历物品在外层循环,遍历背包容量在内层循环?

之前的博客整理过,01背包遍历物品必须在外层循环,原因是一维dp的写法,背包容量是倒序遍历为了不重复放入[j-weight[i]]的物品),而如果遍历背包容量放在上一层,那么每个dp[j]就只会放入一个物品,即:背包里只放入了一个物品

01背包物品在内的情况:(01背包容量倒序

在这里插入图片描述
DAY45:动态规划(六)背包问题优化:一维DP解决01背包问题_大磕学家ZYX的博客-CSDN博客

在完全背包中,对于一维dp数组来说,其实两个for循环嵌套顺序是无所谓的!

原因完全背包,背包容量的for循环是正序遍历,是dp[j] 是根据 下标j之前所对应的dp[j]计算出来的。 只要保证下标j之前的dp[j]都是经过计算的就可以了。

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

蓝色字体是dp[3]dp[4]的推导过程。

在这里插入图片描述
遍历背包容量在外层循环,遍历物品在内层循环,状态如图:

蓝色字体是dp[3]的推导过程,绿色字体是dp[4]的推导过程。

在这里插入图片描述
根据上图结果可以看出,因为完全背包是背包正序遍历,因此即使背包循环在外面,dp[3]dp[4]的推导也不受影响。相当于避免了01背包里面,颠倒遍历顺序会只放进去一个物品的问题

完全背包中,两个for循环的先后循序,都不影响计算dp[j]所需要的值这个值就是下标j之前所对应的dp[j])。

01背包里,因为dp[j]计算需要dp[j-weight[i]],而如果j在外层,遍历到dp[j]的时候,dp[j-weight[i]]根本没有数据。因此会出现问题。但完全背包正序遍历,并不影响dp[j-weight[i]]的数值。因此可以颠倒。

for嵌套顺序颠倒的遍历写法

背包在外层,物品在内层的遍历写法:

  • 注意颠倒嵌套顺序的写法,需要注意下标越界问题!
for(int j=0;j<=bagWeight;j++){
    for(int i=0;i<weight.size();i++){
        if(j-weight[i]) //注意颠倒嵌套顺序的写法,需要注意下标越界问题!
        	dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
    }
}

测试示例

常规遍历顺序:

// 先遍历物品,在遍历背包
void test_CompletePack() {
    vector<int> weight = {1, 3, 4};
    vector<int> value = {15, 20, 30};
    int bagWeight = 4;
    
    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]);
        }
    }
    cout << dp[bagWeight] << endl;
}
int main() {
    test_CompletePack();
}

for颠倒的遍历顺序:

// 先遍历背包,再遍历物品
void test_CompletePack() {
    vector<int> weight = {1, 3, 4};
    vector<int> value = {15, 20, 30};
    int bagWeight = 4;

    vector<int> dp(bagWeight + 1, 0);

    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]);
        }
    }
    cout << dp[bagWeight] << endl;
}
int main() {
    test_CompletePack();
}

面试题目

可能出的面试题目为,纯完全背包,要求先用二维dp数组实现,然后再用一维dp数组实现,最后再问,两个for循环的先后是否可以颠倒?为什么?

纯完全背包问题里,for循环可以颠倒,但是01背包不行。

原因是,01背包里,因为dp[j]计算需要dp[j-weight[i]],而如果j在外层,遍历到dp[j]的时候,dp[j-weight[i]]根本没有数据。因此会出现问题。

但纯完全背包问题,是正序遍历,遍历到dp[j]的时候,dp[j-weight[i]]的数值已经计算完成。因此可以颠倒。

总结

注意,全文说的都是对于纯完全背包问题其for循环的先后循环是可以颠倒的

但如果题目稍稍有点变化,就会体现在遍历顺序上。

如果问装满背包有几种方式的话, 那么两个for循环的先后顺序就有很大区别了

如果我们先遍历背包后遍历物品,得到的就是方案的排列数;先遍历物品再遍历背包,得到的就是方案组合数。这个结论可以在后面的例题:518.零钱兑换Ⅱ 377.组合总和Ⅳ中进行进一步的理解。

原理参考:【总结】用树形图和剪枝操作理解完全背包问题中组合数和排列数问题_先遍历物品后遍历背包是组合数_Calculus2022的博客-CSDN博客

因此并不是所有的完全背包题目,for循环都能颠倒。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自动生成spring-configuration-metadata.json文件

在开发过程中为避免重复修改代码&#xff0c;往往将代码中容易发生变更的值提取出来放到配置文件中。例如数据库连接信息&#xff0c;使用Http调用第三方应用的网关地址等信息。 使用Sprin Boot的ConfigurationPropertie 从配置文件中读取属性值方法多样&#xff0c;这里介绍…

【反向代理】反向代理及其作用

反向代理及其作用 一、什么是正向代理 在介绍反向代理之前我们先介绍什么是正向代理 首先要明确的是&#xff0c;在http协议中正向代理一般被称为代理&#xff0c;在web服务中我们可以通过主动配置代理服务器的方式来发送请求&#xff0c;并通过代理服务器接收服务器的响应。…

自学网络安全(成为黑客)

一、前言 黑客这个名字一直是伴随着互联网发展而来&#xff0c;给大家的第一印象就是很酷&#xff0c;而且技术精湛&#xff0c;在网络世界里无所不能。目前几乎所有的公司企业甚至国家相关部门都会争相高薪聘请技术精湛的黑客作为互联网机构的安全卫士&#xff0c;所以黑客也…

umi框架的使用

umi框架的使用 安装npm i -g yrm 查看yarn镜像源yrm ls 切换源 yrm use taobao 创建项目 yarn create umijs/umi-app 安装依赖yarn 启动项目yarn start 路由组件还可以进行children进行子路由渲染 打个比方&#xff0c;现在有头部导航跟侧边是一致的我们只希望修改每个应…

Mybatis-Plus详解

目录 一、Mybatis-Plus简介 &#xff08;一&#xff09;什么是Mybatis-Plus &#xff08;二&#xff09;Mybatis-Plus的优势 &#xff08;三&#xff09;Mybatis-Plus的框架结构 二、SpringBoot整合Mybatis-Plus入门 &#xff08;一&#xff09;创建maven工程&#xff0c;…

爬虫+Flask+Echarts搭建《深度学习》书评显示大屏

爬虫FlaskEcharts搭建《深度学习》书评显示大屏 1、前言2、实现2.1 挑选想要采集的书籍2.2 构建爬虫2.2.1 采集书籍信息2.2.2 采集书评 2.3 数据清洗2.3.1 清洗书籍信息2.3.2 清洗书评信息 2.4 统计分析&#xff0c;结果持久化存储2.5 搭建flask框架2.6 数据传值2.7 完整代码&a…

什么是Nginx的反向代理与正向代理详解

文章目录 1、什么是正向代理2、什么是反向代理3、反向代理的作用 1、什么是正向代理 正向代理&#xff0c;“它代理的是客户端”&#xff0c;是一个位于客户端和目标服务器之间的服务器&#xff0c;为了从目标服务器取得内容&#xff0c;客户端向代理服务器发送一个请求并指定…

汽车网卡驱动之TJA1101B

TJA1101B汽车网卡驱动(汽车以太网) 1总体描述 2特点和优点 2.1通用 2.2针对汽车用例优化

酷炫音乐盒: python打造自己的音乐播放器

目录标题 前言代码实现尾语 前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! Python的Tkinter&#xff08;Tk接口&#xff09;是一个用于创建图形用户界面&#xff08;GUI&#xff09;的标准库。 它是Python的内置模块&#xff0c;无需额外安装即可使用。Tkinter提供了一组…

【字节青训pre】后端笔试练兵

文章目录&#xff1a; 零、前言一、选择题二、编程题1、36进制转换a) 题目b) 解题思路 零、前言 好久没更博客了 &#xff0c; 暑假参加字节青训营&#xff0c;记录一下备战经历&#xff0c;水水博客 。 因该博客持续更新&#xff0c;文中部分链接是写该博客时预存占坑位的&…

【雕爷学编程】Arduino动手做(147)---QMC5883L三轴罗盘模块2

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

基于Python+Django+mysql+html学生成绩管理系统

基于PythonDjangomysqlhtml学生成绩管理系统 一、系统介绍二、功能展示1.用户登陆2.主页3.年级管理4.班级管理5.课程管理6.学生管理7.班级管理8.学生管理 三、其它系统四、获取源码 一、系统介绍 成绩录入测试账号&#xff1a;test 密码&#xff1a;123 在线成绩录入&#xff…

redis -速成

目录 &#xff08;一&#xff09;认识 Redis 1.1数据库分类 1.2 什么是Redis 1.2.1 redis简介 1.2.2 谁在用Redis 1.2.3 怎么学redis 1.2.4 Redis的安装 2 数据类型 2.1 概况 2.2 String类型 2.2.1 常用的命令 2.2.2 非常用命令 2.2.3 举例 2.2.4应用场景&#xf…

面试之双亲委派原理

一面腾讯提问:如果我自定义一个 new Object 类&#xff0c;请问这个类是否会被加载&#xff1f; 回答&#xff1a;不会&#xff0c;因为双亲委派&#xff0c;向上加载。回答的过程中磨磨唧唧。当然最后一面也是没有过。 总之一句话&#xff1a;向上加载&#xff0c;向下委派. …

【Linux操作系统】死锁

文章目录 死锁的概念产生死锁问题的必要条件如何避免死锁 有两个小朋友站在超市的零食区&#xff0c;手上各拿着五毛钱&#xff0c;他们直勾勾的看着眼前的棒棒糖&#xff0c;问了问阿姨&#xff0c;这个棒棒糖要一块钱。所以a对b说&#xff1a;“你把你的五毛钱给我买棒棒糖”…

Spring Cloud Hystrix简单实用

文章目录 一、简介二、快速开始1、pom依赖2、启动类注解3、服务降级配置HystrixCommand4、配置熔断策略5、测试 三、原理分析四、实际使用 一、简介 Hystrix&#xff0c;英文意思是豪猪&#xff0c;全身是刺&#xff0c;刺是一种保护机制。Hystrix也是Netflflix公司的一款组件。…

Controller配置总结与RequestMapping

1.Controller 2.ResquestMapping 就一个父级目录与自己目录的一个关系&#xff01;&#xff01;&#xff01;理清楚就好了&#xff0c;很好理解&#xff01;

MURF20100CTR-ASEMI快恢复对管MURF20100CTR

编辑&#xff1a;ll MURF20100CTR-ASEMI快恢复对管MURF20100CTR 型号&#xff1a;MUR20100CTR 品牌&#xff1a;ASEMI 芯片个数&#xff1a;2 封装&#xff1a;TO-220F 恢复时间&#xff1a;50ns 工作温度&#xff1a;-50C~150C 浪涌电流&#xff1a;200A 正向电流&am…

[JVM] 2. 类加载子系统(1)-- 内存结构、类加载子系统概述

一、内存结构 类加载子系统的职责是&#xff1a;加载class文件到内存中。 完整的内存结构如下&#xff1a; 二、类加载过程 类加载过程总体分为Loading&#xff08;加载&#xff09;、Linking&#xff08;链接&#xff09;、Initialization&#xff08;初始化&#xff09;三…

【力扣每日一题】2023.7.15 四数之和

题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 这题和本月出过的每日一题&#xff1a;两数之和&#xff0c;三数之和类似。 不夸张的说只要把三数之和的代码拿来再套层for循环改改就可以了。 不过我这里还是简单捋一捋思路&#xff0c;题目给一个数组&#xff0c;要求…