每天一个算法学习之0-1背包算法
每天一个算法学习之0-1背包算法
一、引言:因为开博客的主要目的之一为笔记,且因为时间问题,所以就不能详细说明了,如果想要沟通,留言讨论。
二、主要参考资料:转载:
(1)百度百科:https://baike.baidu.com/item/%E8%83%8C%E5%8C%85%E9%97%AE%E9%A2%98/2416931?fr=aladdin
(2)https://www.cnblogs.com/yun-an/p/11037618.html
(3)https://segmentfault.com/a/1190000012829866
三、算法问题描述:百度百科:
问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。问题的名称来源于如何选择最合适的物品放置于给定背包中。
四、解决思路:动态规划方法:四个步骤:
步骤1-找子问题:主要核心:子问题确定为背包容量为j时,求前i个物品所能达到最大价值。
步骤2-确定状态:由上述分析,“状态”对应的“值”即为背包容量为j时,求前i个物品所能达到最大价值,设为dp[i][j]。
步骤3-确定状态转移方程:
- j<w,dp[i][j] = dp[i-1][j] //背包装不下该物品,最大价值不变
- j>=w, dp[i][j] = max{ dp[i-1][j-list[i].w] + v, dp[i-1][j] } //和不放入该物品时同样达到该体积的最大价值比较
步骤4-优化算法:可以将二维数组优化为一维数组
想法:1.第一遍看完,没懂,尤其是这个状态转移方程是咋来的呀。
2.参考转载(3)的问题分析,挺详细的。第一遍好像懂了一些。切记需要跟着写一遍,就清晰了,光想是理不出的。教训。
3.总结一下转载(3)的问题分析,讲了啥。从举个实例和状态表的角度,使用动态规划思路,一步一步的推导出状态转移方程。
五、算法理论总结:
算法核心为:1.每个物品是否需要放入背包,进行分析。
2.两种情况,背包当前体积小于物品,维持之前的总价值。
3.大于时,进行比较,不放当前物品和放当前物品,
4.其中放当前物品的背包总价值为:当前物品价值+(当前体积-当前物品体积)下之前状态的最高价值。那个大,取那个。
注:当我敲我以上我认为的算法核心时,我认为你没看懂。0.0
六、代码实现:
网上示例代码很多,这里还是贴一下,见最后。
0. 先说一下总价值f[i][j]的内容,i为物品编号,从0至最大-1.j为当前背包体积,从0至w,w为最大体积。
1. 先初始化总价值中第一个物品的i=0的总价值。使用一个for循环,循环次数背包体积j,循环体,一个判断,为0还是物品值。
2. 将状态转移方程中的递归思路转换成循环思路。递归是由最后找到最前,循环是类似递归的已经找到了最前,再依次将值一个个的算到最后得到最后的值。
4.当前循环需要二层循环,因为第一层递归的循环中,需要比较最大值,而比较最大值需要循环得到之前状态的最高价值。
5.这样思路清晰了(我清晰了0.0),第一层循环是关于i的循环,循环次数为:物品数量。循环体为:判断当前物品是否需要放入背包。
6.第二层循环是关于j的循环,确定每个物品下对应各个体积下的最大值。
注:这里只是我的理解,因为我也还看到先循环j的,理解思路问题吧,你如果有兴趣也可以去探究一下,
七、示例代码:(c++)
#include<cstdio> struct Thing { int w; int v; }list[101]; int f[101][1001]; int main() { int s, n;//背包容量和物品总数 while (scanf("%d%d", &s, &n) != EOF) { for (int i = 1; i <= n; i++) { scanf("%d%d", &list[i].w, &list[i].v);//读入每个物品的体积和价值 } for (int i = 0; i <= s; i++) f[0][i] = 0;//初始化二维数组 for (int i = 1; i <= n; i++)//循环每个物品,执行状态转移方程 { for (int j = s; j >= list[i].w; j--) { f[i][j] = f[i - 1][j] > (f[i - 1][j - list[i].w] + list[i].v) ? f[i - 1][j] : (f[i - 1][j - list[i].w] + list[i].v); } for (int j = list[i].w - 1; j >= 0; j --) { f[i][j] = f[i - 1][j]; } } printf("%d\n", f[n][s]); } return 0; }