zoukankan      html  css  js  c++  java
  • 菜鸟都能理解的0-1背包问题的空间优化

    转载:http://www.cfanz.cn/index.php?c=article&a=read&id=51269

    如果你不知道什么叫做0-1背包问题,下面是0-1背包问题的简单描述

    假设有n件物品

    每件物品的体积为w1, w2……wn

       相对应的价值为 v1, v2.……vn。

    01背包是在n件物品取出若干件放在空间为total_weight的背包里,使得背包的总体积最大

    关于0-1背包问题没有优化版本,请看这里

    上面的核心代码是下面这一段

      for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= total_weight; j++) {
          if (w[i] > j) {
            c[i][j] = c[i-1][j];
          } else {
              if (c[i-1][j] > v[i]+c[i-1][j-w[i]]) {
                c[i][j] = c[i-1][j];
              }
              else {
                c[i][j] =  v[i] + c[i-1][j-w[i]];
              }
          }
        }
      }



    注意到状态转移方程 c[i][j] = max{c[i-1][j], c[i-1][j-w[i]]+v[i]}

    每一次c[i][j]改变的值只与c[i-1][x] {x:1...j}有关c[i-1][x]是前一次i循环保存下来的值,因此,可以将c缩减成一维数组
    状态转移方程转换为 c[j] = max(c[j], c[j-w[i]]+v[i]);
    并且,我们注意到状态转移方程,每一次推导c[i][j]是通过c[i-1][j-w[i]]来推导的,而不是通过c[i][j-w[i]]
    因此,j的扫描顺序应该改成从大到小

    因为新的c[i]需要上一轮的c[i-w[j]]辅助计算,而i-w[j] < i,又c为一维数组,因此如果从前往后更新会导致c[i-w[j]]被新的c[i-w[j]]覆盖,从而导致参与帮助计算c[i]的不是上一轮的c[i-w[j]],而是新的c[i-w[j]],则最后计算的c[i]显然不会是正确结果,所以需要从后往前更新。

    否则,第i次求c数组,必然先求的c[j-w[i]]的值(即c[i][j-w[i]]),再求c[j](即c[i][j])的值

    由于j递增,那么状态方程就成为下面这个样子了

    c[i][j] = max(c[i-1][j], c[i][j-w[i]]+v[i])显然不符合题意
    所以,上面的代码变为



     

     for (int i = 1; i <= n; i++) {
        for (int j = total_weight; j >= 1; j--) {
          if (w[i] > j) {
            c[j] = c[j]; //表示第i次与第i-1次相等,这里因为c[j]本来就保存这上一次的值,所以这里不需变化
          } else {
            //说明第i件物品的重量小于背包的重量,所以可以选择第i件物品放还是不放
              if (c[j] > v[i]+c[j-w[i]]) {
                c[j] = c[j];
              }
              else {
                c[j] =  v[i] + c[j-w[i]];
              }
          }
        }
      }



    最后我们可以做下优化,把不必要的语句去掉即可完成优化

    for (int i = 1; i <= n; i++) {
      for (int j = total_weight; j >= w[i]; j--) {
        if (c[j] <= v[i] + c[j-w[i]])
          c[j] = v[i] + c[j-w[i]];
      }
    }


    如此优美的代码简直无法想象!

    注意,空间优化版本最后是求解不出来最优解序列的,但是能求出最优解,也就是最大价值

  • 相关阅读:
    使用duilib链接错误 _declspec(dllimport)
    USB磁盘VID和PID 对应到次盘盘符相关文章
    路径拆分函数
    COM问题
    将对话框嵌入父窗体
    duilib的caption上的Edit无法激活
    LoadLibrary失败,GetLastError MOD_NOT_FOUND
    windows字符串
    windows界面库种类
    windows插件框架
  • 原文地址:https://www.cnblogs.com/ldjhust/p/3150734.html
Copyright © 2011-2022 走看看