【夜深人静学习数据结构与算法 | 第十二篇】动态规划——背包问题

 

目录

 前言:

 01背包问题:

二维数组思路:

一维数组思路:

总结:


 前言:

      在前面我们学习动态规划理论知识的时候,我就讲过要介绍一下背包问题,那么今天我们就来讲解一下背包问题。

在这里我们只介绍01背包,至于分组背包和混合背包这种的已经属于竞赛级别的了,难度过高,我们在这里就不学习了。

【夜深人静学数据结构与算法 | 第十篇】动态规划_我是一盘牛肉的博客-CSDN博客

 01背包问题:

该问题的背景是一个背包和一组物品,每个物品都有自己的价值和重量。目标是选择一些物品放入背包中,使得放入的物品总重量不超过背包的容量,且总价值最大化。

具体来说,给定 n 个物品,其重量分别为 w1, w2, …, wn,价值分别为 v1, v2, …, vn,以及一个背包的容量 W。如何在不超过背包容量的情况下拿到的物品可以实现价值最大?

我们还是严格按照动态规划五步走来确定解题思路:

二维数组思路:

1.dp数组的含义以及下标的含义:dp[i][j]的含义为把[0,i]的物品放到容量为j的背包里 的最大价值。

  • 如果不放当前第 i 个物品,那么此时的最大价值就是 dp[ i-1] [ j ]
  • 如果放当前第 i 个物品,那么此时的最大价值就是 dp [ i-1 ][ j-weight[i]] + value[i]

2.递推公式的推导:dp[i][j]= max(dp[ i-1] [ j ],dp [ i-1 ][ j-weight[i]] + value[i])

3.dp数组的初始化:对于dp数组应该如何初始化,我们可以用画图的方式来表示一下dp数组

 

如果此时我们动态规划到红色的这块区域,由dp数组的公式 dp[i][j]= max(dp[ i-1] [ j ],dp [ i-1 ][ j-weight[i]] + value[i])我们可以知道,这块红色的区域的值一定是由整个数组的左上角区域慢慢推过来的。因此在开始我们就要把左上角的全部初始化,防止出现减不了的情况:

 

 而具体的初始化值,我们简单想一想就可以知道,当背包容量为0的时候,就装不了东西,那么最大价值就是0,那么我们就把竖行的值初始化为0,也就是dp[i][0]初始化为0,横行就是始终装物品0,那么只要背包的容量大于物品0的容量,最大的价值就是dp[0][j]=value.(物品0)。

4.dp数组遍历顺序:对于二维数组的这两个for循环,无论是先便利背包还是物品都是可以的。

那么用一个例子来实现一下动态规划:

#include <iostream>
#include <vector>

using namespace std;

// 定义物品结构体,包含重量和价值
struct Item {
    int weight;
    int value;
};

int knapsack(int W, vector<Item>& items) {
      int size = items.size();
      vector<vector<int>> dp(n + 1, vector<int>(W + 1, 0));

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= W; j++) {
            // 当前物品重量大于背包容量,无法放入背包
            if (items[i - 1].weight > j) {
                dp[i][j] = dp[i - 1][j];
            }
            else {
                // 考虑放入或不放入当前物品的两种情况,取最大值
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - items[i - 1].weight] + items[i - 1].value);
            }
        }
    }

    return dp[n][W]; // 返回最优解
}

int main() {
    int W = 10; // 背包容量

    vector<Item> items = { {2, 6}, {2, 10}, {3, 12} }; // 物品列表

    int maxValue = knapsack(W, items); // 求解最优解

    cout << "最大总价值为: " << maxValue << endl;

    return 0;
}

一维数组思路:

在一维数组优化中,我们只需要创建一个长度为背包容量+1的一维数组,用于记录在不超过当前背包容量下的最优解。具体优化过程如下:

原始的二维dp数组定义为dp[n + 1][W + 1],其中dp[i][j]表示在前i个物品中选择不超过重量j的物品时的最优解。

将二维dp数组优化为一维数组dp[W + 1],其中dp[j]表示在不超过背包容量j的情况下的最优解。

优化后的代码示例:

#include <iostream>
#include <vector>

using namespace std;

// 定义物品结构体,包含重量和价值
struct Item {
    int weight;
    int value;
};

int knapsack(int W, vector<Item>& items) {
    int n = items.size();

    // 创建一维dp数组并初始化为0
    vector<int> dp(W + 1, 0);

    for (int i = 0; i < n; i++) {
        for (int j = W; j >= items[i].weight; j--) {
            // 考虑放入或不放入当前物品的两种情况,取最大值
            dp[j] = max(dp[j], dp[j - items[i].weight] + items[i].value);
        }
    }

    return dp[W]; // 返回最优解
}

int main() {
    int W = 10; // 背包容量

    vector<Item> items = { {2, 6}, {2, 10}, {3, 12} }; // 物品列表

    int maxValue = knapsack(W, items); // 求解最优解

    cout << "最大总价值为: " << maxValue << endl;

    return 0;
}

在上述代码中,我们使用一个长度为背包容量+1的一维数组dp[W + 1]来记录在不超过当前背包容量下的最优解。在计算时,我们从后往前遍历物品,并从后往前更新一维dp数组。这样可以确保在更新dp[j]时,所需的dp[j - items[i].weight]已经是前一轮的值,并且不会影响当前轮的计算结果。通过这种方式,可以实现将二维dp数组优化为一维数组的目的,并得到正确的最优解。

总结:

        本文我们学习了01背包,其实我们可以发现动态规划题目还是有比较强的套路性的,我们把动态规划拆分成为了五部,我们只要按照这五步进行,实际上解决动态规划题目还是很简单的。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

 

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

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

相关文章

视频怎么改成gif格式?简单几步就可以轻松视频转gif

平时我们使用的许多gif图片&#xff0c;其实都是视频片段&#xff0c;那么是怎么把视频转gif格式的呢&#xff1f;可以使用视频转gif工具来完成gif制作&#xff0c;下面就给大家分享一个简单的视频转gif在线制作&#xff08;https://www.gif.cn&#xff09;的方法&#xff0c;一…

如何离线安装ModHeader - Modify HTTP headers Chrome插件?

如何离线安装ModHeader - Modify HTTP headers Chrome插件&#xff1f; 1.1 前言1.2 打开Chrome浏览器的开发者模式1.3 下载并解压打包好的插件1.4 解压下载好的压缩包1.5 加载插件1.6 如何使用插件? 1.1 前言 ModHeader 是一个非常好用的Chrome浏览器插件&#xff0c;可以用…

webpack基础知识四:说说webpack中常见的Plugin?解决了什么问题?

一、是什么 Plugin&#xff08;Plug-in&#xff09;是一种计算机应用程序&#xff0c;它和主应用程序互相交互&#xff0c;以提供特定的功能 是一种遵循一定规范的应用程序接口编写出来的程序&#xff0c;只能运行在程序规定的系统下&#xff0c;因为其需要调用原纯净系统提供…

深度学习——常见注意力机制

1.SENet SENet属于通道注意力机制。2017年提出&#xff0c;是imageNet最后的冠军 SENet采用的方法是对于特征层赋予权值。 重点在于如何赋权 1.将输入信息的所有通道平均池化。 2.平均池化后进行两次全连接&#xff0c;第一次全连接链接的神经元较少&#xff0c;第二次全连…

校园跑腿小程序为什么这么受欢迎呢?

校园跑腿小程序是一种在校园内提供快递、代购、代拿快递、代办事项等服务的手机应用程序。它通常由学生或校园内的志愿者组成&#xff0c;通过该应用程序接受用户的委托&#xff0c;并且根据用户的需求完成任务。校园跑腿小程序通过与学校或社区合作&#xff0c;提供便利的服务…

【JVM技术指南】「GC内存诊断-故障问题排查」一文教你如何打印及分析JVM的GC日志(实战分析上篇)

一文教你如何打印及分析JVM的GC日志 JVM GC日志格式JVM GC日志含义JVM GC日志分析方法开启JVM-GC日志的启动参数GC查看案例JVM参数解析配置JVM参数对象是如何分配在Eden区内存区域分析初始化数组对象 结论 当我们在开发Java应用程序时&#xff0c;JVM的GC&#xff08;垃圾回收&…

【PCL-6】PCL基于凹凸型的分割算法

凹凸型分割算法适用于颜色类似、棱角分明的物体场景分割。 算法流程&#xff1a; 1、基于超体聚类的过分割&#xff1b; 2、在超体聚类的基础上再聚类。 示例代码&#xff1a; //超体聚类LCCP //#include "stdafx.h"#include <stdlib.h> #include <cm…

分布式系统监控Zabbix

分布式系统监控Zabbix 一、Zabbix监控1.什么是Zabbix2.Zabbix功能3.Zabbix运行机制4.Zabbix的三种架构5.Zabbix工作原理及数据走向6.zabbix监控模式 二、Zabbix部署1.安装&#xff0c;部署准备2.zabbix图形化页面显示设置 三、Zabbix监控使用1.安装zabbix监控客户端2.服务端验证…

【第五章 flutter学习之flutter进阶组件-上篇】

文章目录 一、列表组件1.常规列表2.动态列表 二、FridView组件三、Stack层叠组件四、AspectRatio Card CircleAvatar组件五、按钮组件六、Stack组件七、Wrap组件八、StatefulWidget有状态组件总结 一、列表组件 1.常规列表 children: const <Widget>[ListTile(leading: …

从到店到到家,本土便利店正在围猎外资三巨头

全家在中国市场接连关店约300多家&#xff0c;7-11关闭或迁移全球市场的门店约1000家&#xff0c;罗森深圳公司2022年疑似亏损近8000万。 近三年来&#xff0c;以全家、7-11和罗森三家为代表的外资便利店企业&#xff0c;正在遭遇中国本土便利店品牌从到店到家的双重围猎。 20…

针对高可靠性和高性能优化的1200V碳化硅沟道MOSFET

目录 标题&#xff1a;1200V SiC Trench-MOSFET Optimized for High Reliability and High Performance摘要信息解释研究了什么文章创新点文章的研究方法文章的结论 标题&#xff1a;1200V SiC Trench-MOSFET Optimized for High Reliability and High Performance 摘要 本文详…

数据结构—图的存储结构

6.图 回顾&#xff1a;数据的逻辑结构 集合——数据元素间除 “同属于一个集合” 外&#xff0c;无其他关系。 线性结构——一个对一个&#xff0c;如线性表、栈、队列 树形结构——一个对多个&#xff0c;如树 图形结构——多个对多个&#xff0c;如图 6.1图的定义和术语 图:…

QT - 建立页面

一、生成页面 二、实现 1.LineEdit 是一个单行输入文本框&#xff0c;为用户提供了比较多的编辑功能&#xff0c;例如选择复制、粘贴。 修改echomode属性为password Push Button(常规按钮) 三、程序 声明全局变量&#xff0c;属于MainWindow private: // 定义了一个指向Ma…

使用vite创建Vue/React前端项目,配置@别名和Sass样式,又快又方便

Vite官方网站&#xff1a;Vite | 下一代的前端工具链 Vite 并不是基于 Webpack 的&#xff0c;它有自己的开发服务器&#xff0c;利用浏览器中的原生 ES 模块。这种架构使得 Vite 比 Webpack 的开发服务器快了好几个数量级。Vite 采用 Rollup 进行构建&#xff0c;速度也更快…

SAM 大模型Colab快速上手【Segment Anything Model】

Google Colab 是一个基于云的 Jupyter 笔记本环境&#xff0c;允许您通过浏览器编写、运行和共享 Python 代码。 它就像 Google 文档&#xff0c;但用于代码。 通过免费版本的 Google Colab&#xff0c;你可以获得带有约 16GPU VRAM 的 Nvidia Tesla T4 GPU&#xff0c;这对于…

SpringMVC的架构有什么优势?——表单和数据校验(四)

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…

算法通关村——迭代实现二叉树的前中后序遍历

前言 递归就是每次执行方法调用都会先把当前的局部变量、参数值和返回地址等压入栈中&#xff0c;后面在递归返回的时候&#xff0c;从栈顶弹出上一层的各项参数继续执行&#xff0c;这就是递归为什么能够自动返回并执行上一层的方法的原因。因此&#xff0c;我们也可以模拟一个…

路由器工作原理(第二十九课)

路由器工作原理(第二十九课) 一图胜过千言 1) 路由:数据从一个网络到另外一个网络之间转发数据包的过程称为路由 2) 路由器:连接不同网络,实现不同网段之间的通信 3)路由表:路由器选择数据的传输路径的依据 原始的路由表 Destination/Mask Proto Pre Cost …

1706. 球会落何处;875. 爱吃香蕉的珂珂;1914. 循环轮转矩阵

1706. 球会落何处 核心思想&#xff1a;判断什么时候球会被卡住&#xff0c;1&#xff0c;当球在最左边的时候&#xff0c;挡板是向左的。2&#xff0c;当球在最右边的时候&#xff0c;挡板是向右的。3&#xff0c;当球当前的挡板是向左的&#xff0c;但是同一行的另一个挡板是…

【王树森】深度强化学习(DRL)课程笔记:P1 基本概念(含gym安装)

课程信息 课程主讲&#xff1a;王树森&#xff08;史蒂文斯理工学院计算机科学系的终身制助理教授&#xff09; 课程内容&#xff1a;基本概念、价值学习、策略学习、Actor-Critic方法、AlphaGo、Monte Carlo (蒙特卡洛) 课程资料&#xff1a;https://github.com/wangshusen/D…