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

news/2024/11/24 6:50:21/

 

目录

 前言:

 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数组并初始化为0vector<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背包,其实我们可以发现动态规划题目还是有比较强的套路性的,我们把动态规划拆分成为了五部,我们只要按照这五步进行,实际上解决动态规划题目还是很简单的。

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

 


http://www.ppmy.cn/news/1006000.html

相关文章

使用隧道HTTP时如何解决网站验证码的问题?

使用代理时&#xff0c;有时候会遇到网站验证码的问题。验证码是为了防止机器人访问或恶意行为而设置的一种验证机制。当使用代理时&#xff0c;由于请求的源IP地址被更改&#xff0c;可能会触发网站的验证码机制。以下是解决网站验证码问题的几种方法&#xff1a; 1. 使用高匿…

STL学习

STL 泛化编程template函数模板类模板 iterator迭代器C array(STL array)容器 STL中文名为标准库,是C标准的规定并且提供了自己编写STL的接口&#xff0c;在编译器实现中统一的分成立几个容器头文件和几个其他的头文件来完成数据结构和算法的抽象&#xff0c;现在编译器使用的是…

集成学习算法是什么?如何理解集成学习?

什么是集成学习&#xff1f; 集成学习通过建立几个模型来解决单一预测问题。它的工作原理是生成多个分类器/模型&#xff0c;各自独立地学习和作出预测。这些预测最后结合成组合预测&#xff0c;因此优于任何一个单分类的做出预测。 机器学习的两个核心任务 任务一&#xff1…

Flink正常消费一段时间后,大量反压,看着像卡住了,但又没有报错。

文章目录 前言一、原因分析二、解决方案 前言 前面我也有提到&#xff0c;发现flink运行一段时间后&#xff0c;不再继续消费的问题。这个问题困扰了我非常久&#xff0c;一开始也很迷茫。又因为比较忙&#xff0c;所以一直没有时间能够去寻找答案&#xff0c;只是通过每天重启…

Consul屏蔽api

consul 没有设置密码 需要屏蔽api&#xff1a;/v1/internal/ui/nodes?dc&token 防止信息泄露 配置config.json {"http_config": {"block_endpoints": ["/v1/internal/ui/nodes"]} }启动consul时使用该配置&#xff1a; consul agent -de…

Go语言在人工智能时代的崭露头角:为何越来越多公司选择使用Go语言?

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to Golang Language.✨✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1…

Unity Image(RawImage) 实现按轴心放大缩小,序列化存储轴心信息,实现编译器窗口保存轴心

工作时分配给我的要实现的功能&#xff0c;写的时候遇到挺多的坑的&#xff0c;在此记录一下 效果 放大缩小的效果 2.编译器扩展窗口记录 实现点 1.Json序列化存储图片轴心位置, 放大倍率&#xff0c;放大所需要的事件 2.用了编译器扩展工具便于保存轴心信息坑点 1.Imag…

实现多线程的三种方式

1. 继承Thread 类实现多线程 想要实现多线程&#xff0c;第一种方法就是通过继承Thread类实现多线程&#xff0c;有以下几步 &#xff08;1&#xff09;我们要先自定义一个类然后继承Thread类&#xff1b; &#xff08;2&#xff09;在继承Trread的类中重写 run 方法&#x…