01背包(一) 01背包(二)动态规划

news2024/11/28 6:06:46

01背包(一) 二维数组

 题目

背包最大重量为4。

物品为:

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

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

创建二维数组,dp[i][j]的含义是任意放入前 i 个物品放进在背包重量为j的时候的最大价值

 递推公式

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

dp[i][j]任意放入前 i 个物品 放进 j容量背包的最大价值) 可以由 dp[i - 1][j]任意放入前 i -1个物品不放物品 i最大价值)和

dp[i - 1][j - weight[i]] + value[i] 任意放入前 i-1 个物品 同时 放物品 i 的最大价值)推出

 初始化

初始化 dp[i][0](任意放入前 i 个物品,同时背包容量为 0 的最大价值),也就是价值 “0” 的那一列。

容量为0,放不了物品,价值为0

初始化 dp[0][j](放入物品0,背包容量为 j 的最大价值),也就是 价值“15”的那四个格子。

//初始化 dp[i][0](放入物品i,背包容量为 0 的最大价值)
for (int j = weight[0]; j <= bagweight; j++) {
    dp[0][j] = value[0];
}

//初始化 dp[0][j](放入物品0,背包容量为 j 的最大价值)
for (int j = 0 ; j < weight[0]; j++) {  
    dp[0][j] = 0;
}

 后面变成,先全赋值为0,省去背包容量为0的初始赋值,然后赋放入物品0的值

// 初始化 dp
vector<vector<int>> dp(weight.size(), vector<int>(bagweight + 1, 0));
for (int j = weight[0]; j <= bagweight; j++) {
    dp[0][j] = value[0];
}

 

总代码

先遍历物品再遍历背包容量

void test_2_wei_bag_problem1() {
    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];
    }

    // weight数组的大小 就是物品个数
    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]);
            //如果容量够,看看加上价值大还是不加上价值大,因为背包是有容量的
        }
    }
    //这个就是右下角,遍历完成的最大价值,因为有0占格子所以-1
    cout << dp[weight.size() - 1][bagweight] << endl;
}

int main() {
    test_2_wei_bag_problem1();
}

 

想法:这也是遍历了每一种 背包容量 和 物品和不放物品 的所有情况了吧,每一种情况都判断出最大价值,由上一次的最大价值推出下一次的最大价值,末尾得出答案。

 02背包(二) 一维数组

可以从二维简化为一维的数组,理由是可以第一行初始化了以后,后面的行可以重复覆盖第一行来得到最后的结果,dp[i][j]只依靠他的左边和正上方推出,变成一维数组不断覆盖后也不影响最终结果的推导(原来二维数组的最右下角是结果)

题目同(一)

递推公式

dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j]。

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

dp[j] 等于 没放入i的最大价值,dp[j - weight[i]] + value[i] 等于 放入i的最大价值

怎么得出的?

原来二维数组的递推公式 dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i],在递推过程中(左到右上到下),遍历物品1的时候,会用物品1其上方,遍历物品0的值,来计算遍历到的这个格子的值。

如果采取覆盖的方式,把二维数组变成一维数组,利用正上方的值变成利用本格的值,利用完后再替换成计算出的结果,就可以只用一行完成多行的计算了。

比如dp[i - 1]变成dp[i]就是这个意思,dp[i][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i]

然后可以再去除i,只留下这样的话就去掉了 i 的维度了,但是还是用到i的,我的理解这是一种简化的写法。然后变成

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

初始化

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

 

遍历顺序

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

从后往前计算 为什么?

正序遍历

dp[1] = dp[1 - weight[0]] + value[0] = 15(这个时候dp[1]=15)

dp[2] = dp[2 - weight[0]] + value[0] = 30

此时dp[2]就已经是30了,意味着物品0,被放入了两次,所以不能正序遍历。

为什么倒序遍历,就可以保证物品只放入一次呢?

倒序就是先算dp[2]

倒序遍历

dp[2] = dp[2 - weight[0]] + value[0] = 15 (数组已经都初始化为0,就是意思这个时候dp[1]=0)

dp[1] = dp[1 - weight[0]] + value[0] = 15

我的理解就是,一维正序遍历中,正在遍历的值会使用前面的值,比如dp[2]使用dp[1]的,一个dp[1]=15,一个等于0,因为是一个是后序初始化为0还没有计算成15,一个是正序先计算了成15了,但不就是要使用前面的值吗?为什么不使用?

原因是正序计算出的15,覆盖后的值而不是覆盖前的值,而dp[2]需要的dp[1]是覆盖前的值。

换成二维数组和他的递归公式dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i],就是,覆盖前的值才是上一列前面的值,覆盖后就是下一列前面的值了。

这也是为啥二维数组正序倒序都可以,而一维数组只能倒序的原因。

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

 

总代码

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

int main() {
    test_1_wei_bag_problem();
}

着实是有些抽象的。。 

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

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

相关文章

openssl生成SM2公私钥对命令详解

&#xff08;1&#xff09;获得openssl支持椭圆曲线算法列表 命令&#xff1a;openssl ecparam -list_curves 返回结果&#xff1a; secp112r1 : SECG/WTLS curve over a 112 bit prime field secp112r2 : SECG curve over a 112 bit prime field secp128r1 : SE…

051:mapboxGL改变bearing和pitch,变换查看视角

第051个 点击查看专栏目录 本示例是介绍演示如何在vue+mapbox中改变bearing和pitch,变换查看视角。bearing:地图的默认方位角(可选,表示 地图视口正上方中心点 在地图上 北偏东 的角度。默认值为 0)。pitch:地图的默认倾斜角度(可选,默认值为 0,范围为 0 ~ 85)。 直…

《持续交付:发布可靠软件的系统方法》- 读书笔记(四)

持续交付&#xff1a;发布可靠软件的系统方法&#xff08;四&#xff09; 第 4 章 测试策略的实现4.1 引言4.2 测试的分类4.2.1 业务导向且支持开发过程的测试4.2.2 技术导向且支持开发过程的测试4.2.3 业务导向且评价项目的测试4.2.4 技术导向且评价项目的测试4.2.5 测试替身 …

如何获取跑腿App源码并定制化你的业务

跑腿App源码是开发送货和快递服务平台的理想起点。它为你提供了一个现成的应用程序框架&#xff0c;可以帮助你快速进入这个竞争激烈的市场。本文将指导你如何获取跑腿App源码&#xff0c;以及如何将其定制化以适应你的业务需求。我们将以一个示例项目为基础进行说明。 步骤1…

故障维修无忧服务:OLED透明拼接屏的专业技术支持与保修服务

OLED透明拼接屏作为未来显示技术的领军者&#xff0c;以其卓越的画质和全方位的优势在市场上备受推崇。 本文将深入探讨OLED透明拼接屏的画质特点和独有的优势&#xff0c;并为您提供选购指南、价格表以及故障维修服务&#xff0c;助您了解并选择最适合的OLED透明拼接屏。 一、…

软考-系统开发基础

软件开发模型 瀑布模型 瀑布模型的优点是&#xff1a;容易理解&#xff0c;管理成本低&#xff1b;签掉开发阶段早期计划及需求调查和产品测试 V模型 V模型是瀑布模型的一个变体 注重测试&#xff0c;但测试放在编码之后 喷泉模型 原型模型 螺旋模型 综合了瀑布模型和原型模…

蔬菜水果生鲜配送团购商城小程序的作用是什么

蔬菜水果是人们生活所需品&#xff0c;从业者众多&#xff0c;无论小摊贩还是超市商场都有不少人每天光临&#xff0c;当然这些只是自然流量&#xff0c;在实际经营中&#xff0c;蔬菜水果商家还是面临着一些难题。 对蔬菜水果商家而言&#xff0c;线下门店是重要的&#xff0…

ubuntu 20.04 使用systemback自定义系统镜像和系统备份

ubuntu 20.04 使用systemback自定义系统镜像和系统备份 Systemback简介1. 安装 systemback16.0418.04 查看 2. 使用 systemback创建自定义镜像制作镜像制作中制作完成将镜像写入U盘 Systemback简介 Systemback是一个简单的系统备份和恢复应用程序&#xff0c;根据GPLv3许可条款…

2023年中国自动驾驶卡车市场发展趋势分析:自动驾驶渗透率快速增长[图]

自动驾驶卡车的技术原理是通过电脑算法控制车辆行驶&#xff0c;辅助驾驶员完成任务。其实现方式主要是基于传感器和计算处理技术。自动驾驶卡车可以随时感知周围环境&#xff0c;灵活避障&#xff0c;自适应调整行驶路径&#xff0c;相比之下传统卡车需要驾驶员进行手动操作&a…

2023最新闪聊远程获取通讯录PHP源码/附安装教程/php即时聊天源码/获取闪聊通讯录源码

源码介绍&#xff1a; 闪聊远程获取通讯录PHP&#xff0c;首先你需要在服务器上搭建Nginxmysql5.6php5.6phpMyAdmin的环境。接着&#xff0c;在app/database.php中配置好数据库路径。最后&#xff0c;在宝塔面板的站点管理中&#xff0c;将伪静态设置为tphinkphp即可。这样一来…

免费office安装工具箱(可安装任意版本)

Office Tool Plus v10.0.5.2 -office安装工具箱 Office Tool Plus是一款相当好用的office安装工具&#xff0c;并且安装完了顺带激活。借助Office Tool Plus&#xff0c;可以一次性安装Office、Visio、Project&#xff0c;还可以选择不同的授权版本。自定义选择Office的组件&a…

QCustomPlot实现曲线拖拽

本文内容目录 需求场景:一、选择控件二、将QCustomPlot库整合到你的Qt项目中1、下载源代码2、创建.pri三、鼠标框选,实现坐标缩放四、曲线拖动1、定位曲线2、移动时改变曲线五、问题的产生与解决1、查看源码2、修改本项目代码需求场景: 曲线图应该同时具有以下功能点: 1、…

聊一聊翻页电子书制作流程

翻页电子书由于比传统纸质书更加方便阅读&#xff0c;又非常利用储存&#xff0c;所以受到了很多人的喜爱。如何制作翻页电子书&#xff1f;今天我们简单聊一聊翻页电子书制作流程。 制作翻页电子书首先我们要有一个好用的工具&#xff0c;比如我们可以借用Flbook在线翻页电子…

vant_ CountDown倒计时

语法可以直接在官网查看 需求 后端返回的数据格式如下 [{"id": 1,"btn_text": "1","second": 0},{"id": 2,"btn_text": "1","second": 0}... ]之前约定second最多30s&#xff0c; 因此只需…

信钰证券:国际油价大涨!美联储将有新动作

鉴于近期美债收益率继续攀升&#xff0c;美联储多位官员在上星期前几日一再开释“鸽派”信号&#xff0c;称再加息的必要性削弱&#xff0c;提振投资者风险偏好&#xff0c;一度推进美国三大股指上涨。之后&#xff0c;巴以抵触局势风云突变&#xff0c;以色列方面计划向加沙地…

win10部署 Mistral-7B 文本生成模型

Mistral 7B date : 2023年10月16日 人工智能创业公司Mistral AI以Apache 2.0授权开源Mistral 7B语言模型&#xff0c;Mistral 7B的特别之处在于其规模较小仅有73亿&#xff0c;但是在所有基准测试上&#xff0c;其表现都优于规模更大的语言模型Llama 2 13B&#xff0c;还具有…

记使用docker部署项目出现问题

我的docker-compose.yml内容如下&#xff1a; version: "3" services:my_server:build: .restart: alwaysdepends_on:mysql:condition: service_startedports:- 9999:9999links:- mysqlmysql:image: mysql:latest # mysql:oraclerestart: alwayscontainer_name: mys…

陈宥维《虎鹤妖师录》“显眼包”太子成长记 表演灵动获好评

由爱奇艺出品&#xff0c;黄晓达同名少年热血漫画改编&#xff0c;郭虎导演&#xff0c;蒋龙、张凌赫、王玉雯、陈宥维主演的古装玄幻剧《虎鹤妖师录》正在热播中。该剧讲述了虎子、祁晓轩、赵馨彤、王羽千等热血少年组团闯关&#xff0c;在一次次降妖和追寻真相的过程中收获成…

CSS 效果:多列文字,第一行对齐,flex方式元素被挤压

如图效果&#xff1a;2列&#xff0c;第一列只有一行&#xff0c;第二列多行。要求第一行对齐 实现&#xff1a;使用flex 如果不配置flex-shrink的话&#xff0c;第一列会被挤压 给第一列&#xff1a;备注配置压缩属性&#xff1a; flex-shrink&#xff1a;0。 <!DOCTYPE…

01简单的CMakeLists.txt示例

CMakeLists.txt 基础 CMake 是一个项目构建工具&#xff0c;并且是跨平台的。关于项目构建我们所熟知的还有Makefile&#xff08;通过 make 命令进行项目的构建&#xff09;&#xff0c;大多是IDE软件都集成了make&#xff0c;比如&#xff1a;VS 的 nmake、linux 下的 GNU ma…