每天一个算法学习之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;
}

 

posted on 2020-09-02 22:39  一次性炮灰  阅读(524)  评论(0编辑  收藏  举报

导航