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]];
      }
    }


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

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

  • 相关阅读:
    Minimum Depth of Binary Tree leetcode java
    Maximum Depth of Binary Tree leetcode java
    Symmetric Tree leetcode java
    Same Tree leetcode java
    Binary Tree Postorder Traversal leetcode java
    Binary Tree Preorder Traversal leetcode java
    Binary Tree Inorder Traversal leetcode java
    Combinations leetcode java
    一键清除Centos iptables 防火墙所有规则
    阿里云centos7.7x64安装open,并配置ip转发和nat伪装
  • 原文地址:https://www.cnblogs.com/ldjhust/p/3150734.html
Copyright © 2011-2022 走看看