【问题标题】:Dynamic Programming Subset Algorithm动态规划子集算法
【发布时间】:2012-06-28 09:50:19
【问题描述】:

我正在编写一些动态编程的复习材料。我需要想出应该如何划分子问题,计算出基本情况,并想出递归公式。

给定 n 个正整数 a1,a2,...,an,一个数 k 和一个目标 W,我们想要选择一个子集 T,其中恰好有 k 个元素的和最接近 W。每个元素只能选择一次.用 3 个参数定义一个子问题(即 C[x,y,z] = ...)。

我只使用过几个动态编程示例,从未使用过需要 3 个参数来定义子问题的示例。我真的迷路了。如果有人能发光,那就太好了。

我对子问题应该是什么的最佳猜测是:

C[x,y,z] = {a1,...ay} 中的 x 个元素,其中总和正好是 z

但我不知道这是否正确。

【问题讨论】:

    标签: algorithm dynamic-programming


    【解决方案1】:

    在这种情况下,我会让 C(x,y,z) 是一个布尔值,表示是否可以使用来自 {a1 ... ax} 的恰好 y 得到恰好 z 的总和。

    虽然不是完全相同的问题Wikipedia,但有各种类似问题的动态规划解决方案并附有解释。也许这会给你一些想法。

    【讨论】:

      【解决方案2】:

      将其分解为三个参数的一种方法是:

      x: maximum index of item considered for inclusion in subset
      n: number of items in subset
      s: sum of subset
      

      基本情况是 C[0,0,0] = true, C[0,i > 0,j > 0] = false

      递归情况是:

      C[i,n+1,s+a_i] = C[i-1,n,s]  // use item i
      C[i,n,s] = C[i-1,n,s] // dont use item i
      

      这使用空间 O(n^2 * max(a_i))(可以通过丢弃 C[i,,] 来减少到 O(n*max(a_i)) )

      然后只需在 C[n,i,j] 中搜索 z 附近的 j 即可获得最终答案。

      作为一个循环...

      for (int i = 1; i <= n; i++)
      {
          C[i,n+1,s+a_i] ||= C[i-1,n,s];
          C[i,n,s] ||= C[i-1,n,s];
      }
      

      作为递归函数:

      bool C(int maxindex, int size, int sum)
      {
          if (memoize(maxindex, size, sum))
               return cached;
      
          if (maxindex == 0)
              return (size == 0 && sum == 0);
      
          return
               C(maxindex-1, size-1, sum - A[maxindex]) ||  // version using A[maxindex]
               C(maxindex-1, size, sum); // version not using A[maxindex]
      }
      

      【讨论】:

      • 嗯,递归函数如何查找这个?我习惯于开发递归函数,然后从那里开始研究伪代码。有没有可能从中得出?一些沿线 C[x,y,z] = { ... }
      • @Telsa:添加循环和递归函数
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-26
      • 2013-11-27
      • 1970-01-01
      • 2015-05-06
      相关资源
      最近更新 更多