【动态规划】0-1背包问题

news/2024/11/28 0:03:14/

概述

0-1背包问题是一种经典的动态规划问题,它的基本形式是:有一个背包,容量为 C C C,有 n n n 个物品 i i i,每个物品 i i i 的重量为 w i w_i wi,价值为 v i v_i vi。现在要从这 n n n 个物品中选出若干个放入背包中,使得背包中物品的总重量不超过 C C C,且物品的总价值最大。

解题思路

这个问题可以用动态规划来解决,一般使用一个二维数组 d p dp dp 来存储最大价值。

d p [ i ] [ j ] dp[i][j] dp[i][j] 表示在前 i i i 个物品中选择若干个物品,恰好放入容量为 j j j 的背包中,可以获得的最大价值。

那么对于每个物品,我们可以选择将其放入背包中,也可以选择不放入。

如果选择将第 i i i 个物品放入背包中,则有 d p [ i ] [ j ] = d p [ i − 1 ] [ j − w i ] + v i dp[i][j] = dp[i-1][j-w_i] + v_i dp[i][j]=dp[i1][jwi]+vi

如果选择不放入,则有 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j] = dp[i-1][j] dp[i][j]=dp[i1][j]。我们需要取这两种情况的较大值作为 d p [ i ] [ j ] dp[i][j] dp[i][j] 的值。

可以得到状态转移方程如下:

dp[i][j]=max⁡(dp[i−1][j−wi]+vi,dp[i−1][j])

最后,最大价值就是 d p [ n ] [ C ] dp[n][C] dp[n][C]

图表分析

书包重量(公斤)012345678
物品不存在000000000
物品1:6公斤、48元000000484848
物品2:1公斤、7元077777484848
物品3:5公斤、40元0777740485555
物品4:2公斤、12元0712191940485560
物品5:1公斤、8元0815202740485663

当物品不存在和书包重量为0的时候,背包价值肯定也为0。

切记:dp[i][j]表示前i个物品、背包承重为j时的最大价值。

前一件物品:只有当背包容量为6的时空才可以装下,所以dp[1][6]=48。由于这是选择的前一件物品,那么在背包容量为7和8时,不会考虑后面的物品,值还是48。

前两件物品:当背包容量为1时,可以装下第二件物品,这时背包价值为7,dp[2][1] = 7。一直到书包承重5公斤时,都只能装下物品2,dp[2][1]到dp[2][5]都是等于7。 书包承重6公斤时,可以装物品1或物品2,两者只能装1个,通过对比物品1和物品2的价值大小,我们选择物品1,即dp[2][6]=48。书包承重7公斤时,可以同时装物品1、物品2,此时dp[2][7]=物品2的价值 + 物品1的价值=55。dp[2][8]也是同样的道理。

前三件物品:背包容量从1到4时,只能装下物品2,即最大价值为7。当背包容量为5时,可以装下物品3,价值为40,当背包容量为6时,只装物品1,背包价值为48。

以此类推,可得到五件物品的情况下,背包能装下且得到的最大价值是多少。

示例代码

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;int knapsack(vector<int>& weights, vector<int>& values, int capacity) {int n = weights.size();vector<vector<int>> dp(n + 1, vector<int>(capacity + 1, 0));for (int i = 1; i <= n; i++) {for (int j = 1; j <= capacity; j++) {if (weights[i - 1] > j) {// 当前物品重量大于背包容量,无法放入,继承上一个最优解dp[i][j] = dp[i - 1][j];} else {// 当前物品可以选择放入或者不放入dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1]);}}}return dp[n][capacity];
}int main() {vector<int> weights = { 6, 1, 5, 2, 1 };vector<int> values = { 48, 7, 40, 12, 8 };int capacity = 8;int result = knapsack(weights, values, capacity);cout << "Max value: " << result << endl;return 0;
}

运行结果如下所示:
在这里插入图片描述

解析:
首先定义了函数knapsack,该函数接受三个参数:物品重量的数组weights、物品价值的数组values和背包容量capacity。函数返回值为能够装入背包的最大价值。

函数内部,首先获取物品的数量n,然后定义了一个dp数组来保存中间计算结果。其中,dp[i][j]表示前i个物品,容量为j时,能够获得的最大价值。

接下来使用两层循环,遍历每一个可能的状态。对于每个状态,如果当前物品重量大于背包容量,则无法放入背包中,继承上一个最优解。否则,当前物品可以选择放入或者不放入背包中。这里使用了max函数来求解当前状态下的最大值。最后返回dp[n][capacity]即可。

在main函数中,定义了物品重量、价值和背包容量的数组,并调用knapsack函数求解最大价值,并输出结果。

总结

0-1背包问题是一个经典的动态规划问题,求解的是一个有限容量的背包所能携带的最大价值。其特点是:每种物品只有一个,可以选择装或不装,不能部分装入。

0-1背包问题可以用动态规划来解决。具体思路如下:

  1. 定义状态:定义 dp[i][j] 表示前 i 个物品放入容量为 j 的背包中所能获得的最大价值。

  2. 初始化状态:dp[0][j] 和 dp[i][0] 都初始化为 0,因为当没有物品或者背包容量为 0 时,所能获得的最大价值为 0。

  3. 状态转移方程:当当前物品重量大于当前背包容量时,无法放入,当前最优解为继承上一个最优解;否则,当前物品可以选择放入或者不放入,取决于两种情况下的最大价值。dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1]);

  4. 返回结果:dp[n][capacity] 表示前 n 个物品放入容量为 capacity 的背包中所能获得的最大价值。

代码实现时,可以使用二维数组 dp[i][j] 来存储状态转移方程的结果,其中 i 表示物品的编号,j 表示背包的容量。初始化时,将 dp[0][j] 和 dp[i][0] 都初始化为 0。最终结果为 dp[n][capacity]。时间复杂度为 O(ncapacity),空间复杂度为 O(ncapacity)。


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

相关文章

深度学习一点通:PyTorch Transformer 预测股票价格,虚拟数据,chatGPT同源模型

预测股票价格是一项具有挑战性的任务&#xff0c;已引起研究人员和从业者的广泛关注。随着深度学习技术的出现&#xff0c;已经提出了许多模型来解决这个问题。其中一个模型是 Transformer&#xff0c;它在许多自然语言处理任务中取得了最先进的结果。在这篇博文中&#xff0c;…

leetcode 54. 螺旋矩阵

题目链接&#xff1a;leetcode 54 1.题目 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 2.示例 1&#xff09;示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,…

Redis可持久化详解2

目录 ​编辑 Redis的持久化配置参数&#xff1a; 2.Redis的性能问题&#xff1a; 3保持久化数据的完整性和正确性&#xff1a; 4.Redis的集群技术&#xff1a; 总结&#xff1a; Redis持久化不得不注意的一些地方。 Redis的持久化配置参数&#xff1a; save&#xff1a;指…

Camtasia2023.0.1CS电脑录制屏幕动作工具新功能介绍

Camtasia Studio是一款专门录制屏幕动作的工具&#xff0c;它能在任何颜色模式下轻松地记录 屏幕动作&#xff0c;包括影像、音效、鼠标移动轨迹、解说声音等等&#xff0c;另外&#xff0c;它还具有即时播放和编 辑压缩的功能&#xff0c;可对视频片段进行剪接、添加转场效果。…

java字符串非英文字母的替换为空格,将空格替换为空字符串,将英文字母按五个拆分一组

可以使用正则表达式来匹配符合条件的字符&#xff0c;然后再进行替换和拆分。具体实现如下&#xff1a; String str "Hello, 123 world! Welcome to Java."; // 将非英文字母替换为空格 str str.replaceAll("[^a-zA-Z]", " "); // 将空格替换…

【综述】结构化剪枝

目录 摘要 分类 1、依赖权重 2、基于激活函数 3、正则化 3.1 BN参数正则化 3.2 额外参数正则化 3.3 滤波器正则化 4、优化工具 5、动态剪枝 6、神经架构搜索 性能比较 摘要 深度卷积神经网络&#xff08;CNNs&#xff09;的显著性能通常归因于其更深层次和更广泛的架…

【改进粒子群优化算法】自适应惯性权重粒子群算法(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

网络安全这条路到底该怎么走?

我之前就写过一篇文章专门解答了这个问题。但是还是有很多小伙伴并不清楚这条路该怎么走下去&#xff01; 不同于Java、C/C等后端开发岗位有非常明晰的学习路线&#xff0c;网路安全更多是靠自己摸索&#xff0c;要学的东西又杂又多&#xff0c;难成体系。 网络安全虽然是计算…