代码之家  ›  专栏  ›  技术社区  ›  Eric Auld

在递归DP中,通过存储变量来分解递归调用:效率低下?

  •  -1
  • Eric Auld  · 技术社区  · 7 年前

    假设我正在递归地(自上而下)解决一个动态编程问题。例如,最长公共子序列问题的递归解:

    LCS(S,n,T,m)
    {
    if (n==0 || m==0) return 0;
    if (S[n] == T[m]) result = 1 + LCS(S,n-1,T,m-1); 
    else result = max( LCS(S,n-1,T,m), LCS(S,n,T,m-1) );
    return result;
    }
    

    通常在这样一个DP问题中,在某一点上,我们必须取一些表达式的最大值,代表我们可以做出的不同选择的返回值。在上面的例子中,我们有两个简单表达式的最大值,但在更糟的情况下,它可以是三个或四个涉及长函数调用的相当复杂的表达式的最大值。在这种情况下,我常常试图给这些复杂的表达式指定自己的变量名,以使代码更具可读性。在上面的情况下,这意味着我会写

    LCS(S,n,T,m)
    {
    if (n==0 || m==0) return 0;
    if (S[n] == T[m]) result = 1 + LCS(S,n-1,T,m-1); 
    else
        a = LCS(S,n-1,T,m);
        b = LCS(S, n, T, m-1); 
        result = max(a, b);
    return result;
    }
    

    (在这种简化的情况下 a b 不复杂,但在其他情况下,它们是复杂的,而且max函数可能有更多的参数,因此这确实有助于它更容易理解。)

    我的问题: 这是个糟糕的主意吗?据我所知,我在调用堆栈的每一层添加一个变量,我认为这可能是浪费。但另一方面,在每一层都要计算临时变量 LCS(S,n,T,m) 不管怎样,(我想用C++来计算),据我所知,这两种方法之间的成本差别不大。

    如果这是一个糟糕的想法,有没有更有效的方法来分解一个复杂的递归函数调用,使其更具可读性?

    0 回复  |  直到 7 年前
        1
  •  1
  •   Caleth    7 年前

    C++有“以貌取人”的规则,它规定编译器只要能观察到的效果与标准所定义的结果不可区分,就可以做任何想做的事情。在这种情况下,证明两个片段具有相同的含义并不重要,编译器可能会为这两个片段发出相同的指令。

    注意:这里不是动态编程,因为你没有记忆参数/结果对。

    推荐文章