动态编程没有给出正确的答案

时间:2016-02-06 16:54:18

标签: python dynamic-programming

我最近发现了一种叫做动态编程的技术,我偶然发现了一个我无法弄清楚的问题。您在开头就会得到一个参数列表,您需要对它进行总结,就像您正在削减它一样。如果列表只有一个元素,那么你就不要总结它。如果它有更多,你总结元素并以各种可能的方式切割它。因此,如果list有n个元素,那么只有n-1种方法可以删除它。图片将解释:

Opt

我首先要总结所有可用的部分,我期望结果20(11 + 9)(甚至认为正确的答案是9),但我认为这将是一个良好的开端。但我的代码返回37号,我不知道为什么。我做错了什么?

summ = 0

def Opt( n ):
    global summ

    if len( n ) == 1:
        return 0
    else:
        summ += sum( n )
        for i in range( 1,len( n ) ):
            summ += Opt( n[ :i ] ) + Opt( n[ i: ] )

        return summ

print( Opt( [ 1,2,3 ] ) )

感谢您的时间和任何答案!

1 个答案:

答案 0 :(得分:5)

我认为这就是你想要的:

def Opt(n):
    if len(n) == 1:
        return 0
    else:
        return sum(n) + min(Opt(n[:i]) + Opt(n[i:])
                            for i in range(1, len(n)))

示例:

>>> Opt([1])
0
>>> Opt([1, 2])
3
>>> Opt([2, 3])
5
>>> Opt([1, 2, 3])
9
>>> Opt([1, 2, 3, 4])
19

动态编程是将“大问题”划分为小的子问题。

因此,首先,您应该确定大问题与子问题的关系。您可以通过编写递归关系来完成此操作。在这种情况下:

Opt(nums) = sum(nums) + min(...)

您还需要一个起点:

Opt(nums) = 0 iff len(nums) == 1

正如您所看到的,一旦您编写了递归关系,将其转换为Python代码通常很简单。

重要的是要理解每个子问题都是独立的,不应该需要外部输入。您对global变量的使用不仅产生了错误的结果,而且违背了动态编程的精神。

您使用树来表达Opt()很不错。你忘记做的是写每个节点和它的孩子之间的关系。如果你这样做了,我几乎可以肯定你自己会找到正确的解决方案。

我们尚未完成(感谢Stefan Pochmann注意)。为了构建真正的动态编程解决方案,您还需要避免多次解决同一问题。目前,正在运行Opt([1,2,3,4])会导致多次调用Opt([1,2])。防止这种情况的一种方法是使用memoization:

cache = {}

def Opt(n):
    # tuple objects are hashable and can be put in the cache.
    n = tuple(n)

    if n in cache:
        return cache[n]

    if len(n) == 1:
        result = 0
    else:
        result = sum(n) + min(Opt(n[:i]) + Opt(n[i:])
                              for i in range(1, len(n)))

    cache[n] = result
    return result

顺便说一句,请记住处理n为空的情况(即len(n) == 0)。