动态规划 01背包问题(简单易懂)
来源:互联网 发布:microsoft画图软件 编辑:程序博客网 时间:2024/05/19 17:56
之前讲过了动态规划的几个例子,分别是动态规划 矩阵连乘问题 和 动态规划 最常公共子序列问题,学习了动态规划的使用,而01背包问题作为动态规划的经典问题,同时对贪心算法也是一个很重要的补充,所以也必须掌握01背包问题的原理和实现。
01背包问题
题目描述:
有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?
分析这个问题,使用动态规划的话,我们首先想得是这个问题能不能分成子问题,然后优化子结构。
ps:动态规划自底向上,所以x轴是从 n-> 1,而y轴是从 1->m
看这个图,紫色部分name表示物品的名字,黄色部分weight表示物品的重量,绿色部分value表示物品的价值,蓝色部分表示承重从1到10的背包,白色部分当前承重的背包所能放入的物品的价值的最大值f[i, j]。
这里首先要说一个01背包状态转换方程:
f[i,j] = Max{ f[i+1,j-Wi]+Vi( j >= Wi ), f[i+1,j] }
- f[i,j]表示在前i件物品中选择若干件放在承重为 j 的背包中,可以取得的最大价值。
- Vi表示第i件物品的价值
这个式子现在不懂没关系,文章下会解释
问题分析
动态规划的要求就是从底向上,最后一行e,e的重量是4,价值为6,因此0-3的背包放不下,4-10的背包放得下,所以0-3背包的价值为0,4-10的背包价值为6。
然后从下往上看第二行,例如d4,表示承重为4的背包所能翻入d,e两个物品的价值的最大值,在这里承重4明显不能放入d,只能放入e,因为d的weight为5,e的weight为4,所以d4的最大值就是放入e时的价值最大值6,以此类推。
再来看a8 = 15,是怎么来的呢?按照公式,求a8则需要求 b6 + Va 和 b8,取其最大值,那么因为动态规划是自底向上的,所以当我们求a哪一行的时候,bcde行都已经求出,因此b6+Va = 15 > b8 = 9,所以a8应该等于15。
这个公式该怎么理解呢?或者说为什么f[i,j] 就一定会等于f[i+1,j-Wi]+Vi 和 f[i+1,j] 的最大值?
我们根据动态规划的思想来思考,使用动态规划,就是因为该问题可以通过分解为子问题的分治思想,求出各个子问题的最优子结构,从而得出我们问题的解。
a8(f[i][j]),表示承重为8的背包放入a-e物品的最大价值,
b6 + Va (f[i+1][j - w[i]] + Vi):表示我有一个承重为6的背包(原承重为8 减去 a的重量2),能放入bcde物品的最大价值,再加上a的重量的最大价值
b8 (f[i+1,j]):表示有一个承重为8的背包,能放入bcde物品的最大价值
这样考虑:我们求a8,用优化子结构的思想,先求预留了a的空间的背包的最大价值,再加上a的价值,不就是我需要求得的背包的最大价值了吗?
放入a之后,背包剩余的空间就是8-2 = 6,那么背包为6时的放入bcde物品的最大价值是9,再加上a的价值6等于15,得出我们承重为8的背包最大价值是15,但是还需要考虑下面这个原则:
在同样的背包承重下,如果放入物品i的背包最大价值小于不放入物品i的背包最大价值,我们选择不放入该物品(因为价值都一样,放入了反而占空间,不放此物品我还可以放其它物品)因此我们还要考虑不放入物品a的情况即b8 (f[i+1,j]),b8 = 9,明显放入a之后价值为15 大于 不放入时的价值9,所以我们选择放入
总结:
由以上分析可得,a8=15
代码实现
#include<iostream>#include<algorithm>using namespace std;const int n = 5;//表示物品的数量 const int m = 10;//表示背包所能承受的重量,从1-10 int weight[n+1] = {0, 2, 2, 6, 5, 4};//物品的重量,前面0下标为0只是为了让下标对齐 int value[n+1] = {0, 6, 3, 5, 4, 6};//物品的价值 int f[n+1][m+1];//表示能承受重量为j的背包放入1-i物品的最大价值 void package01(){ int i = n, j; //首先对最底下的进行填充 for(j = 1; j <= m; j++){ if(j < weight[i]){ f[i][j] = 0; }else{ f[i][j] = value[i]; } } //然后对剩下的n-1个物品填充 for(i = n -1; i > 0; i--){ for(j = 1; j <= m; j++){ if(j < weight[i]){ f[i][j] = f[i+1][j]; }else{ f[i][j] = max(f[i+1][j-weight[i]] + value[i], f[i+1][j]); } } } for(i = 1; i <= n; i++){ for(j = 1; j <= m; j++){ cout << f[i][j] << " "; } cout << endl; } cout << "承重为10的背包最大价值是:" << f[1][10];}int main(){ package01();}
- 动态规划 01背包问题(简单易懂)
- 动态规划之0-1背包问题(简单易懂)
- 从01背包问题理解动态规划(看过最简单易懂的版本)
- 01背包问题(动态规划DP)
- 01背包问题(动态规划)
- 一道01背包问题(动态规划)
- 01背包问题(动态规划)
- 01背包问题(动态规划)
- 动态规划(01背包问题)
- 动态规划--01背包问题(1)
- 动态规划--01背包问题(2)
- 01背包问题(动态规划DP)
- 动态规划之背包问题(一):01背包问题
- 简单易懂的背包问题
- 简单0-1背包问题(算法类别:动态规划)
- 动态规划之简单背包问题
- 动态规划--01背包问题
- 动态规划--01背包问题
- js解析json添加到表格并分页
- SQL语句的增删改查
- Android 百度云推送
- 常用SQL优化
- WKWebView添加cookie
- 动态规划 01背包问题(简单易懂)
- MyDocument.exe病毒查杀方法
- 自学iOS开发系列----OC(block)
- 设置页弹框背景不透明问题分析及解决
- 从LAMP到框架式开发的SOA:土巴兔8年架构之道
- 从Vuex中取出数组赋值给新的数组,新数组push时报错
- Kotlin:Android世界的Swift
- 工作流
- JavaScript立即执行函数表达式(IIFE)