Python 更多关于动态规划的信息

Python 更多关于动态规划的信息,python,dynamic-programming,memoization,Python,Dynamic Programming,Memoization,两周前,我在这里发布了关于动态规划的问题。用户准确地回答了我想要的问题,但我想进一步解决这个问题 这是我的职责 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,2,3,4,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,2,3,4,5 ] )
前面的问题解决了计算最优值的问题。现在, 我不想在上面的例子中计算最优值33,而是想打印得到最优解的方式(最优解的路径)。因此,我想打印列表被切割/分割的索引,以列表的形式得到最优解。因此,上述例子的答案是:

[3,2,1,4]
(在第三个标记/索引处,然后在第二个索引之后,然后在第一个索引之后,最后在第四个索引处切割极/列表)。 答案应该是列表形式的。列表的第一个元素是索引,在该索引中,列表的第一次切割/分割应发生在最佳路径中。第二个元素是列表的第二个切割/分割,依此类推

也可以有不同的解决方案:

[ 3,4,2,1 ] 
它们都会引导您获得正确的输出。所以,你打印哪一个并不重要。但是,我不知道如何跟踪和打印动态规划解决方案所采用的最佳路径。 顺便说一句,我找到了一个非递归的解决方案,在我的前一个问题中解决了这个问题。但是,我仍然无法找到打印最优解决方案的路径。这是前一个问题的非递归代码,它可能有助于解决当前问题

def Opt(numbers):
prefix = [0]
for i in range(1,len(numbers)+1):
    prefix.append(prefix[i-1]+numbers[i-1])
results = [[]]
for i in range(0,len(numbers)):
    results[0].append(0)
for i in range(1,len(numbers)):
    results.append([])
    for j in range(0,len(numbers)):
        results[i].append([])
for i in range(2,len(numbers)+1): # for all lenghts (of by 1)
    for j in range(0,len(numbers)-i+1): # for all beginning
        results[i-1][j] = results[0][j]+results[i-2][j+1]+prefix[j+i]-prefix[j]
        for k in range(1,i-1): # for all splits
            if results[k][j]+results[i-2-k][j+k+1]+prefix[j+i]-prefix[j] < results[i-1][j]:
                results[i-1][j] = results[k][j]+results[i-2-k][j+k+1]+prefix[j+i]-prefix[j]
return results[len(numbers)-1][0]
def Opt(数字):
前缀=[0]
对于范围(1,长度(数字)+1)内的i:
prefix.append(前缀[i-1]+数字[i-1])
结果=[]]
对于范围(0,len(数字))中的i:
结果[0]。追加(0)
对于范围(1,len(数字))中的i:
结果。追加([])
对于范围(0,len(数字))内的j:
结果[i]。追加([])
对于范围(2,长度(数字)+1)内的i:#对于所有长度(of乘以1)
对于范围(0,len(数字)-i+1)内的j:#对于所有开始
结果[i-1][j]=结果[0][j]+结果[i-2][j+1]+前缀[j+i]-前缀[j]
对于范围(1,i-1)中的k:#对于所有拆分
如果结果[k][j]+结果[i-2-k][j+k+1]+前缀[j+i]-前缀[j]
以下是打印所选内容的一种方法:

我在上一个问题中使用了@Andrea Corbellini提供的使用记忆的递归解决方案。如下所示:

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
selectedList = []
def printSelected (n, low):

    if len(n) == 1:
        # No need to print because it's 
        # already printed at previous recursion level.
        return

    minVal = math.Inf
    minTupleLeft = ()
    minTupleRight = ()
    splitI = 0

    for i in range(1, len(n)):
        tuple1ToI = tuple (n[:i])
        tupleiToN = tuple (n[i:])

        if (cache[tuple1ToI] + cache[tupleiToN]) < minVal:
            minVal = cache[tuple1ToI] + cache[tupleiToN]
            minTupleLeft = tuple1ToI
            minTupleRight = tupleiToN
            splitI = low + i


    print minTupleLeft, minTupleRight, minVal
    print splitI   # OP just wants the split index 'i'.
    selectedList.append(splitI) # or add to the list as requested by OP

    printSelected (list(minTupleLeft), low)
    printSelected (list(minTupleRight), splitI)
printSelected (n, 0)
现在,我们有了所有元组(包括选定元组)的缓存值

使用此选项,我们可以打印所选元组,如下所示:

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
selectedList = []
def printSelected (n, low):

    if len(n) == 1:
        # No need to print because it's 
        # already printed at previous recursion level.
        return

    minVal = math.Inf
    minTupleLeft = ()
    minTupleRight = ()
    splitI = 0

    for i in range(1, len(n)):
        tuple1ToI = tuple (n[:i])
        tupleiToN = tuple (n[i:])

        if (cache[tuple1ToI] + cache[tupleiToN]) < minVal:
            minVal = cache[tuple1ToI] + cache[tupleiToN]
            minTupleLeft = tuple1ToI
            minTupleRight = tupleiToN
            splitI = low + i


    print minTupleLeft, minTupleRight, minVal
    print splitI   # OP just wants the split index 'i'.
    selectedList.append(splitI) # or add to the list as requested by OP

    printSelected (list(minTupleLeft), low)
    printSelected (list(minTupleRight), splitI)
printSelected (n, 0)

这就像一篇博客文章。你的问题是什么?值得一提的是,找到一个动态规划解决方案的“路径”比仅仅找到解决方案要困难得多。@cat如何在我explained@TheTask1337不仅是你的“问题”被埋在一堵不必要的文字墙里,这并不能帮助我理解我为什么要读这篇文章,但对于一个母语为英语的人来说,问题陈述本身几乎是不可理解的。请尽量准确地指出您希望得到的帮助,并加以解释,以便临时观察者了解情况。@cat在管理员重新设置我的问题后,可能会更清楚。谢谢你,谢谢你,但这并不是我想要的。问题在于线条:print n[splitI]我想要的是切割的位置,而不是切割的元素。所以我试着将它改为:print n.index(n[splitI]),但问题是,它与原始列表无关,因为当函数递归调用自身时,原始列表将拆分,我们不再有关于它的信息。因此,对于输入[7,6,5,4,3,2,1],输出可以是例如:[2,1,4,3,5,6],但我只能得到:[2,1,2,1,1,1],它工作正常,但不能做我想要的。谢谢你,好的。我能修好那部分。我不清楚你想要什么。我将更新并通知您。谢谢,但请注意,输入可以包含多个唯一编号,因此输入也可以是例如[1,4,14,12,3,4,5,3]。我已更新了答案。现在,它跟踪索引。一旦你尝试这个,请更新我。我正在将索引附加到selectedList。