• 背包问题


    0-1背包

    问题描述:

      有n个重量和价值分别是wi,vi的物品,从这些物品中挑选出总重量不超过W的物品,求所有方案中价值总和的最大值

    分析:

      dp[ i ][ j ] 表示在前 i 个物品中能装入容量为 j 的背包的最大价值,则有:

      dp[i][j] = dp[i - 1][j]    j < wi
      dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - wi] + vi)    j >= wi

      当前背包容量不允许装入第 i 件物品时,前 i 件和前 i-1 件一样,允许装入时,从两种选择(装、不装)中挑选价值最大的

    优化及拓展:

      在计算 dp[i][j] 时只使用了 dp[i-1][0……j] ,在存储子问题解的时候,只用存储 dp[i-1] 的子问题解即可,所以可以使用滚动数组进行空间优化,用一维数组代替二维,只不过一维的数组,一个是代表正在解决的问题(左边的是 i ),一个是代表子问题(右边的是 i - 1)。即状态转移方程可以这样表示:dp[j] = max(dp[j], dp[j - w[i]] + v[i]); 

      注意点:若使用滚动数组优化成一维,则 j 的遍历,即背包容量的枚举需要逆序枚举,因为一维数组正序计算时存在值的覆盖(i-1时刻的值会被当前 i 时刻的值覆盖),会使得结果错误。而二维数组标明了是 i 时刻的值还是 i-1 时刻的值,所以正序逆序都无所谓

    完全背包

     问题描述:

      在0-1背包的基础上,每种物品可以取任意个

    分析:

      完全背包问题的dp思想可以在0-1背包的基础上改进,增加一个描述选取物品数量的参数,这样的话还需要枚举数量参数的可取值,效率不高

    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= w; j++)
        {
            for(int k = 0; k * w[i] <= j; k++)
            {
                if(w[i] <= j)
                    dp[i][j] = max(dp[i][j], dp[i - 1][j - k * w[i]] + k * v[i]);
                else
                    dp[i][j] = dp[i - 1][j];
            }
        }
    }

      虽然在这基础上可以再进行一系列的优化,比如有两种物品,其中一种价值小且重量大,那么就可以把这种物品删除不考虑等等,但是在随机数据中,这种优化效果并不显著,现更换一种dp思路,将完全背包问题转化成0-1背包来解决。

      上面这种k参数的方法是以每一种物品为单位来枚举每种取多少个来解决的,而现在以每一个物品为单位来看问题,考虑是否在物品总数中添加当前该物品,来看递推式

      f [ i ] [ j ] = max( f[ i - 1 ] [ j ] , f [ i ] [ j - c[i] ] + w [ i ] )

      为什么会是f[i][j-c[i]]+w[i],因为你放第i种物品,并不牵扯到第i-1种物品

     1 for (int i = 1; i <= n; ++i)
     2 {
     3     for (int j = 1; j <= v; ++j)
     4     {
     5         if (c[i] <= j)
     6             f[i][j] = max(f[i - 1][j], f[i][j - c[i]] + v[i]);
     7         else
     8             f[i][j] = f[i - 1][j];
     9     }
    10 }

    优化及拓展:

      空间优化一下,和0-1背包问题不同的是,0-1背包空间优化后遍历顺序是逆序,而这里完全背包问题则是需要顺序。

      考虑一下原因,在未考虑第 i 种物品的时候,前面的 i - 1 种物品存在一个最优解,当考虑第 i 种物品的添加时,可能最优解会更新,所以需要顺序来覆盖更新最优解

    1 for (int i = 1; i <= n; ++i)
    2 {
    3     for (int j = w[i]; j <= v; ++j)
    4     {
    5         f[j] = max(f[j], f[j - c[i]] + v[i]);
    6     }
    7 }

    参考博客:

    http://www.cnblogs.com/Kalix/p/7617856.html

    https://www.cnblogs.com/Kalix/p/7622102.html

  • 相关阅读:
    Linux系统中/和是什么意思,和window系统有什么区别?
    给自己的U盘设定图标
    我的第一篇文章
    大端小端
    好玩的地图
    英语流利说 第28天
    英语流利说 第27天
    英语流利说 第26天
    英语流利说 第25天
    英语流利说 第24天
  • 原文地址:https://www.cnblogs.com/friend-A/p/10318400.html
Copyright © 2020-2023  润新知