动态编程/递归 - 理解杆切割

时间:2016-05-24 03:57:31

标签: algorithm recursion dynamic-programming

在经典的杆切割问题中,最大收益的数学表达式是: enter image description here

可以递归地定义为:

maxCost(n) = max(p[n], (maxCost(n-i)+maxCost(i), for 1 <= i <= n)

可表示为:

p = [1, 5, 8, 9]
def maxCost(size):
    if size <= 1:
        return size
    cost = -1
    for i in xrange(1, size+1):
        cost = max(p[i-1], (maxCost(i) + maxCost(size-i-1))) # --> stackoverflow error
        #cost = max(cost, (p[i-1]+ maxCost(size-i))) --> giving correct o/p
    return cost

if __name__ == '__main__':
    print maxCost(4)

循环中未注释成本的表达式直接来自定义的数学表达式。但是,这会产生错误。

另一方面,评论成本的表达式给出了正确的答案(对于n = 1,2,3,4),但是我无法从数学表达式中理解该表达式的推导。 / p>

任何人都可以帮助/告诉我未注释的表达式中的成本以及注释行的正确性和原因是什么?

2 个答案:

答案 0 :(得分:3)

你确定递归

maxCost(n) = max(p[n], (maxCost(n-i)+maxCost(i), for 1 <= i <= n) 

是对的吗?

基于http://www.radford.edu/~nokie/classes/360/dp-rod-cutting.html,递归是

q = max(q, p(i) + Cut-Rod(p, n-i)

这与您的评论行匹配

cost = max(cost, (p[i-1]+ maxCost(size-i)))

回答您关于为何看到SO错误的问题......

您正在使用的未注释的递归

cost = max(p[i-1], (maxCost(i) + maxCost(size-i-1)))

两次致电maxCostisize-i-1

即使输入为2,这也会使您无限递归。 我在你的代码中加了几个print语句来说明会发生什么。

p = [1, 5, 8, 9]
def maxCost(size):
    print("maxCost called with size= " + str(size));
    if size <= 1:
        return size
    cost = -1
    for i in xrange(1, size+1):
        print("in loop, i= " + str(i));
        raw_input("Press Enter to continue...")
        cost = max(p[i-1], (maxCost(i) + maxCost(size-i-1))) # --> stackoverflow error
        #cost = max(cost, (p[i-1]+ maxCost(size-i))) --> giving correct o/p
    return cost

if __name__ == '__main__':
    size = int(raw_input().strip())
    print maxCost(size)

输入大小为2时的输出。

H:\code\temp>py so.py
2
maxCost called with size= 2 #initial call size=2
in loop, i= 1
Press Enter to continue...
maxCost called with size= 1
maxCost called with size= 0
in loop, i= 2
Press Enter to continue...
maxCost called with size= 2 #called again with size=2, when i=2
in loop, i= 1
Press Enter to continue...

你会注意到当i = 2时,我们又回到了调用maxCost(2),这与我们第一次调用maxCost完全相同!因此无限递归和SO错误。

正确的递归将在n-1处停止。

rk=max(pk,r1+rk−1,r2+rk−2,…,rk−1+r1)

在上面的等式(取自http://www.radford.edu/~nokie/classes/360/dp-rod-cutting.html)中,在pk之后,确切地存在k-1项,所以我们必须仅从1循环到k-1。因此for i in xrange(1, size): #fixed to iterate to size-1

此外,在原始代码中,在计算成本时,您还需要将成本也包含在max()函数的输入中,否则您将失去上一次迭代中计算的成本。因此,cost = max(cost, p[size-1], (maxCost(i) + maxCost(size-i)))

完整的固定代码为1到4的大小提供了正确的值。 注意:对于size = 4,正确的输出是10,而不是9。

p = [1, 5, 8, 9]
def maxCost(size):
    if size <= 1:
        return size
    cost = -1
    for i in xrange(1, size): #fixed to iterate to size-1
        cost = max(cost, p[size-1], (maxCost(i) + maxCost(size-i))) # --> fixed code, gives correct out of 10, for size=4
        #cost = max(cost, (p[i-1]+ maxCost(size-i))) #--> giving correct o/p
    return cost

if __name__ == '__main__':
    size = int(raw_input().strip())
    print maxCost(size)

答案 1 :(得分:1)

maxCost(i)

你的函数在相同的深度级别调用自身,因此它永远不会达到基本情况。

maxCost(1) -> maxCost(1) -> maxCost(1) -> ad infinitum 

导致堆栈溢出