【问题标题】:What can be a newbie explanation for a dynamic programming?动态规划的新手解释是什么?
【发布时间】:2015-08-15 07:47:36
【问题描述】:

我正在尝试学习动态编程 (DP) 的基础知识,并浏览了一些我可以获得的在线资源,例如...

  1. What is dynamic programming?
  2. Good examples, articles, books for understanding dynamic programming
  3. Tutorial for Dynamic Programming
  4. Dynamic Programming – From Novice to Advanced --(我无法正确理解(即如何使用 DP 解决问题))

直到现在我才明白

动态问题几乎与 递归只是有区别(这赋予了它已知的力量

存储我们获得的价值或解决方案并再次使用它来寻找下一个解决方案

例如:

根据codechef的解释

问题:最小步数

问题陈述:对于一个正整数,您可以执行以下 3 个步骤中的任何一个。

  1. 从中减去 1。 ( n = n - 1 )
  2. 如果它可以被 2 整除,则除以 2。(如果 n % 2 == 0 ,则 n = n / 2)
  3. 如果它可以被 3 整除,则除以 3。(如果 n % 3 == 0 ,则 n = n / 3)

现在的问题是,给定一个正整数 n,求从 n 到 1 的最小步数

例如:

  1. 对于 n = 1 ,输出:0
  2. 对于 n = 4 ,输出:2 ( 4 /2 = 2 /2 = 1 )
  3. 对于 n = 7 ,输出:3 ( 7 -1 = 6 /3 = 2 /2 = 1 )

    int 备忘录[n+1]; // 我们将元素初始化为 -1(-1 表示尚未解决)

针对上述问题的自顶向下方法

int getMinSteps ( int n ) {
    if ( n == 1 )  return 0;
    if( memo[n] != -1 ) return memo[n];
    int r = 1 + getMinSteps( n - 1 );
    if( n%2 == 0 )   r  =  min( r , 1 + getMinSteps( n / 2 ) );
    if( n%3 == 0 )   r  =  min( r , 1 + getMinSteps( n / 3 ) );
    memo[n] = r ;  // save the result. If you forget this step, then its same as plain recursion.
    return r;
}

我对 dp 的理解是否正确,或者任何人都可以用更好更简单的方式解释它,以便我可以学习它并可以使用动态编程解决问题。

【问题讨论】:

    标签: dynamic-programming


    【解决方案1】:

    来自维基百科的Fibonacci sequence 例子就是一个很好的例子。

    动态规划是一种优化技术,假设问题满足principle of optimality,它将潜在的指数递归解决方案转换为多项式时间解决方案。基本上意味着您可以从最佳子问题构建最佳解决方案。 动态规划可以处理的问题的另一个重要特征是它们是overlapping。如果将这些问题分解为重复的子问题,则可以重复使用相同的解决方案来解决这些子问题。 具有最优子结构属性和重叠子问题的问题,动态规划是一种潜在的有效解决方法。

    在示例中,您可以看到斐波那契数的递归版本将在树状结构中增长,这意味着指数爆炸。

    function fib(n)
           if n <=1 return n
           return fib(n − 1) + fib(n − 2)
    

    所以对于fib(5),你会得到:

    fib(5)
    fib(4) + fib(3)
    (fib(3) + fib(2)) + (fib(2) + fib(1))
    

    以类似树的方式等等。

    动态编程让我们可以在多项式时间内使用最优子问题逐步构建解决方案。这通常通过某种形式的记录保存来完成,例如表格。 注意子问题有重复的实例,即计算一次fib(2)就足够了。

    同样来自维基百科,一种动态编程解决方案

    function fib(n)
       if n = 0
           return 0
       else
           var previousFib := 0, currentFib := 1
           repeat n − 1 times // loop is skipped if n = 1
               var newFib := previousFib + currentFib
               previousFib := currentFib
               currentFib  := newFib
       return currentFib
    

    这里的解决方案是由最初设置的previousFibcurrentFib 构建的。 newFib 是根据此循环中的先前步骤计算得出的。 previousFibcurrentFib 代表我们为之前的子问题保留的记录。

    结果是一个多项式时间解(在这种情况下为 O(n)),用于递归公式为指数的问题(在这种情况下为 O(2^n))。

    【讨论】:

      【解决方案2】:

      有精彩回答How should I explain dynamic programming to a 4-year-old? 只是在这里引用相同的内容:

      在一张纸上写下“1+1+1+1+1+1+1+1 =”

      “那等于什么?”

      计数“八!”

      在左边写下另一个“1+”

      “那怎么办?” “九!”

      “你怎么知道九点这么快?”

      “你刚刚又加了一个”

      “所以你不需要重新计算,因为你记得有 八! 动态编程只是表达“记住”的一种奇特方式 以后可以节省时间的东西'

      【讨论】:

        猜你喜欢
        • 2014-08-11
        • 2012-01-01
        • 2010-11-07
        • 1970-01-01
        • 2011-03-03
        • 2013-03-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多