01背包—动态规划

news2025/1/17 2:52:48

一、背包问题概述:

请添加图片描述

二、暴力解法:

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

背包最大容量为4。

每一个物品有两个状态,“取”或者“不取”。利用回溯法可以暴力枚举所有物品的状态的排列组合状态,与背包最大容量比较就可以求得最大的价值,时间复杂是 O ( 2 n ) O(2^n) O(2n)为指数级别,故需要动态规划的解法来进行优化。

三、二维DP数组解01背包

1.DP数组含义

dp[i][j]:任取编号为[0,i]内的物品,放到容量为j的背包内所得到的最大价值。

2.递推公式(对dp[i][j]

  1. 不放物品idp[i][j]=dp[i-1][j]
  2. 放物品idp[i][j]=dp[i-1][j-weight[i]] + value[i]

dp[i][j]最终应该取放物品i和不放物品i中大的那一个值。

故,dp[i][j]=max(dp[i-1][j], dp[i-1][j-weight[i]]+value[i])

3.DP数组解析

请添加图片描述
如图,对于dp[i][j](红色表格),其取值由两个方向得到:

  1. dp[i][j]=dp[i-1][j],由1号红色箭头得到;
  2. dp[i][j]=dp[i-1][j-weight[i]] + value[i],由2号箭头得到。具体2号箭头的初始位置则由weight[i]决定。

所以,求解DP数组时[i-1]必须是已知的,故DP数组初始化时第一行必须初始化。

第一列不需要初始化,使用if判断j-weight[i] > 0 即可。

综上,初始化时,只初始化第一行,其余位置皆不用初始化。

就本题而言,初始化数组为:
请添加图片描述

4.遍历顺序

i先遍历物品再遍历背包

请添加图片描述
本方法本质是按行遍历,对每个物品从容量0j逐个测试。由DP数组解析可得,求dp[i][j]时必须知道dp[i-1][0~j]内的所有数据,而这在前一次循环中已经得到。故该遍历方法可行。

ii先遍历背包再遍历物品

请添加图片描述 本方法本质是按列遍历,对每个容量从物品0i逐个测试。由DP数组解析可得,求dp[i][j]时必须知道dp[i-1][0~j]内的所有数据,而这在前一次循环中已经得到。故该遍历方法可行。

5. 代码:

void knapsack () {
    vector<int> weight = {1, 3, 4};  // 物品重量
    vector<int> value = {15, 20, 30};  // 物品价值
    int bagweight = 4;  // 背包的最大容量
    // 创建二维数组
    vector<vector<int>> dp(weight.size(), vector<int>(bagweight + 1, 0));
    // 初始化
    for (int j = weight[0]; j <= bagweight; j++) {
        dp[0][j] = value[0];
    }
    // 先遍历物品
    for(int i = 1; i < weight.size(); i++) { // 遍历物品
        for(int j = 0; j <= bagweight; j++) { // 遍历背包容量
            if (j < weight[i]) dp[i][j] = dp[i - 1][j];
            else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
        }
    }
    // 先遍历背包
    // for(int j = 0; j <= bagweight; j++) { // 遍历背包容量
    //    for(int i = 1; i < weight.size(); i++) { // 遍历物品
    //        if (j < weight[i]) dp[i][j] = dp[i - 1][j];
    //         else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
    //     }
    // }
    cout << dp[weight.size() - 1][bagweight] << endl;
}

四、一维DP数组(滚动数组)解01背包

1.DP数组含义

从二维DP数组的遍历图中可以看出求解dp[i][j]完全是在使用DP数组的前一行(或前一列)的数据,且对dp[i][j]后面的内容完全不关心。因此,可以考虑将前一行(或前一列)的数据覆盖到当前行,使用一行(或一列)就可以完成计算,这就是本题一维DP数组的思想。

本题定义dp[j]为容量为j的背包能装物品的最大价值(相当于将二维数组压缩为一行)。

2.递推公式

  1. 不放物品idp[j]=dp[j](可以将等号后dp[j]的看作上一行的数据,只是覆盖到了当前行)
  2. 放物品idp[j]=dp[j-weight[i]]+value[i](可以将等号后的dp[j-weight[i]]看作上一行的数据,只是覆盖到了当前行)

dp[j]=max(dp[j], dp[j-weight[i]]+value[i])

3.DP数组初始化

由数组的定义可知,求dp[j]只需知道其前面的数据即可。考虑一下,最“前面”的数据就是背包不放任何物体。故将DP数组所有元素设置为0即可。

4.遍历顺序

因为当前DP数组的值可以看成为上一行的覆盖,故为了保持dp[j]前的元素的“干净”,遍历j时应该采用倒叙遍历。
请添加图片描述
如图,蓝色代表当前行已经更新的值,红色代表当前行正要求的值,绿色代表上一行还没有更新的值。从后往前遍历可以保证对dp[j]更新时,其前面的值都不会被改变。如果采用正序遍历,相当于dp[j]前的值为当前行的值(这种说法也不对,物品i的值被累加了),递推公式就不成立了。

假设物品重量{1, 1},价值{5, 10},背包最大容量为4。如图,若采用正序遍历
请添加图片描述
在第二行更新DP时,由于dp[j]前的数据已经被污染,故每次更新dp[j]时都对物品1的价值进行了累加。而倒叙时由于前面数据没有被污染,则不会产生累加的错误。如图:
请添加图片描述

5.代码

void test_1_wei_bag_problem() {
    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 = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
            dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
        }
    }
    cout << dp[bagWeight] << endl;
}

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

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

相关文章

Cloudflared 内网穿透 使用记录

Cloudflared 内网穿透前提创建cloudflared tunnel我使用的服务前提 你必须要有一个域名&#xff0c;并且可以改域名的dns解析服务商到cloudflare 1.登录到cloudflare后台&#xff0c;点击添加站点 2.输入自己的域名&#xff0c;下一步选择免费套餐 3.他会搜索这个域名下已有…

iOS自动化打包

测试阶段一般会发生这样的场景&#xff0c;测试拼命的提 Bug&#xff0c;开发拼命的改 Bug&#xff0c;改完重新打包发给测试进行复测&#xff0c;那这个过程中频繁的打包肯定是不可避免的。如果使用 Xcode 打包&#xff0c;在打包期间我们是无法改剩余的 Bug 或进行其他模块的…

大规模 IoT 边缘容器集群管理的几种架构-3-Portainer

前文回顾 大规模 IoT 边缘容器集群管理的几种架构-0-边缘容器及架构简介大规模 IoT 边缘容器集群管理的几种架构-1-RancherK3s大规模 IoT 边缘容器集群管理的几种架构-2-HashiCorp 解决方案 Nomad大规模 IoT 边缘容器集群管理的几种架构-3-Portainer &#x1f4da;️Reference…

你好,Cartesi 社区资助计划

这是一个由社区驱动的计划&#xff0c;它将为贡献者提供资金&#xff0c;并且可以帮助建立和扩展 Cartesi的生态系统对于那些一直在寻求支持以实现他们想法的开发人员&#xff0c;那些有兴趣帮助建设塑造我们发展生态系统的Cartesi 爱好者们。我们很兴奋的宣布我们推出了Cartes…

【华为OD机试模拟题】用 C++ 实现 - 新学校选址(2023.Q1)

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

Java 的 JDBC 编程

一、数据库编程的必备条件二、Java 的数据库编程 JDBC三、JDBC 工作原理四、JDBC 使用4.1 下载驱动包4.2 打开编辑器&#xff0c;添加依赖4.3 编写连接数据库代码一、数据库编程的必备条件 编程语言&#xff0c;例如 Java、C、C、Python 等.数据库&#xff0c;如 Oracle、MySQ…

机器学习------ 基于ubuntu 22.04 系统下的pytorch 安装记录过程(包含cuda和cudnn的安装)

机器学习----- pytorch的安装过程 最近&#xff0c;在学习机器学习&#xff0c;在对于理论方面进行一段时间的学习后&#xff0c;打算开始上手代码。在此之前&#xff0c;选择了pytorch作为学习的工具&#xff0c;这里记录下安装的过程。在这里&#xff0c;先把我的设备展示一…

乌卡时代的云成本管理:从0到1了解FinOps

在上一篇文章中&#xff0c;我们介绍了企业云业务的成本构成以及目前面临的成本困境&#xff0c;以及当前企业逐步转向 FinOps 的行业趋势&#xff0c;这篇文章我们将详细聊聊 FinOps&#xff0c;包括概念、重要性以及成熟度评价指标。 随着对云服务和供应商的使用越来越多&…

2023年博管办香江学者计划、澳门青年学者开始申报

2023年2月20日&#xff0c;全国博士后管委会办公室官方网站发出了2023年香江学者计划、澳门青年学者计划和博士后国&#xff08;境&#xff09;外学术交流项目申报指南&#xff0c;以下知识人网小编仅转载香江学者计划和澳门青年学者计划申报指南并做重点解读。知识人网整理香江…

分布式之gossip共识算法分析

写在前面 假如你的业务对系统的可用性要求非常高&#xff0c;就算集群只剩下一个节点&#xff0c;也要能够正常对外提供服务&#xff08;虽然此时系统能力已经骤降&#xff0c;但至少还在&#xff01;&#xff09;&#xff0c;因为raft 要求大多数节点可用所以就没有用武之地了…

【2223sW1】LOG1

这里写自定义目录标题写在前面23.2.19报错Unable to allocate xxx GiB for an array with shape (xxxx, xxxx)23.2.20psi6图片绘制选择了部分r&#xff0c;绘制了g6&#xff08;r&#xff09;23.2.21从lammpstrj文件中导出了1001X6个csv文件虚拟内存扩展代码运行占用资源查询写…

字符串转换为二进制-课后程序(JAVA基础案例教程-黑马程序员编著-第五章-课后作业)

【案例5-4】 字符串转换为二进制 【案例介绍】 1.任务描述 本例要求编写一个程序&#xff0c;从键盘录入一个字符串&#xff0c;将字符串转换为二进制数。在转换时&#xff0c;将字符串中的每个字符单独转换为一个二进制数&#xff0c;将所有二进制数连接起来进行输出。 案…

PowerJob容器的今生,容器是如何部署到Worker上,并正常运行的

这仅仅是一篇PowerJob源码分析的文章&#xff0c;但是也有一些java基础知识&#xff0c;在实践中学习效果更好&#xff0c;感兴趣就留下来交流一下吧。 上回书说到&#xff0c;这个powerjob容器是如何生成模板&#xff0c;如何上传到服务器上去&#xff0c;本回主要总结的是&am…

死磕Node模块兼容性,ESM和CJS我全都要!

目录 前言 一些概念 CJS&#xff08;CommonJS&#xff09; ESM&#xff08;ECMAScript Modules&#xff09; 兼容操作 效果演示 总结 前言 在Node版本13.2.0&#xff08;2019年&#xff09;之前&#xff0c;我们一般使用CJS&#xff08;CommonJS&#xff09;模式在代码…

Java JDBC详解

1、JDBC概念、本质、好处 概念&#xff1a; JDBC 就是使用Java语言操作关系型数据库的一套API 全称&#xff1a;( Java DataBase Connectivity ) Java 数据库连接 本质&#xff1a; 官方&#xff08;sun公司&#xff09;定义的一套操作所有关系型数据库的规则&#xff0c;即接口…

展现AI与自动化测试技术之间的神奇化学反应

目录 零&#xff1a;前言 一、介绍 1.1、什么是自动化测试技术 1.2、痛点 1.3、几款优秀的自动化测试工具介绍 1.3.1、Selenium 1.3.2、龙测AI-TestOps云平台 1.3.3、TestCafe 二、实操 2.1、主要功能模块介绍 2.2、实战演练 2.2.1、创建web项目 2.2.2、录制流程图…

Taro3.x 容易踩坑的点(阻止滚动穿透,弹框蒙层父级定位)

解决弹框滚动的时候&#xff0c;下层也会滚动问题》阻止滚动穿透(react,vue)案例描述&#xff1a;页面展示时需要滚动条才可以显示完整&#xff0c;但是当我们显示弹框的时候&#xff0c;即使不需要滚动条&#xff0c;但是页面仍然可以滚动&#xff0c;并且下层内容会随着滚动变…

MES助力灯具照明行业从制造到”智造”

现如今&#xff0c;LED照明行业产品更新换代太快&#xff0c;一个产品一两年不更新一下外观、材料&#xff0c;就会被对手超越。这直接导致LED产品标准化程度不够高&#xff0c;LED下游制造类厂家智能化生产程度普遍偏低。 加之大多属于劳动密集型产业&#xff0c;传统的依靠买…

Hive分区表与分桶表的使用具体说明

目录 一、分区表 (一)分区表基本语法 1.创建分区表 2.往分区表中写入数据的两种方法 (1)load装载本地数据 (2)insert...select...(常用) 3.读取分区表数据 4. Hive分区表的存储路径规划&#xff1a;分区字段分区值 5.分区表基本操作 (1)查看所有分区信息 (2)新增分区…

C#使用MQTT通信 .Net实现MQTT通信 java使用MQTT通信 java实现MQTT通信

MQTT是一种轻量级、基于发布/订阅模式的通信协议&#xff0c;通常用于物联网设备间的通信。MQTT协议采用简单的二进制消息格式&#xff0c;能够在不占用过多网络带宽的情况下进行高效的通信。以下是使用MQTT进行通信的一些基本概念&#xff1a;BrokerMQTT通信中的中间件&#x…