【问题标题】:Unable to implement a dynamic programming table algorithm in python无法在python中实现动态规划表算法
【发布时间】:2012-02-09 23:46:35
【问题描述】:

我在 python 中创建表时遇到问题。基本上我想建立一个表格,每个数字都告诉我是否可以用它来分解另一个数字(它的表格算法来自Can brute force algorithms scale? 中接受的答案)。这是伪代码:

for i = 1 to k
    for z = 0 to sum:
        for c = 1 to z / x_i:
            if T[z - c * x_i][i - 1] is true:
                set T[z][i] to true

这是我的python实现:

from collections import defaultdict


data = [1, 2, 4]
target_sum = 10

# T[x, i] is True if 'x' can be solved
# by a linear combination of data[:i+1]
T = defaultdict(bool)           # all values are False by default
T[0, 0] = True                # base case


for i, x in enumerate(data):    # i is index, x is data[i]
    for s in range(target_sum + 1): #set the range of one higher than sum to include sum itself
        for c in range(s / x + 1):  
            if T[s - c * x, i]:
                T[s, i+1] = True

#query area   
target_result = 1
for node in T:
    if node[0]==target_result:
        print node, ':', T[node]

所以我期望的是,如果 target_result 设置为 8,它会显示列表 data 中的每个项目如何用于分解该数字。对于所有工作的 8、1、2、4,所以我希望它们都是真实的,但是这个程序正在使一切变为真实。例如,1 应该只能被 1(而不是 2 或 4)分解,但是当我将它作为 1 运行时,我得到:

(1, 2) : True
(1, 0) : False
(1, 3) : True
(1, 1) : True

谁能帮我理解代码有什么问题?或者我可能不理解我所指的答案中发布的算法。

(注意:我可能完全错了,但我了解到 defaultdict 会创建条目,即使它不存在,如果条目存在,算法会将其变为真,也许这就是我不确定的问题,但它是我试图走的思路,但它对我不起作用,因为它似乎破坏了整体实施) 谢谢!

【问题讨论】:

    标签: python algorithm dynamic-programming


    【解决方案1】:

    如果您使用RecursivelyListAllThatWork() 打印解决方案,则代码有效:

    coeff = [0]*len(data)
    def RecursivelyListAllThatWork(k, sum): # Using last k variables, make sum
        # /* Base case: If we've assigned all the variables correctly, list this
        # * solution.
        # */
        if k == 0:
            # print what we have so far
            print(' + '.join("%2s*%s" % t for t in zip(coeff, data)))
            return
        x_k = data[k-1]
        # /* Recursive step: Try all coefficients, but only if they work. */
        for c in range(sum // x_k + 1):
           if T[sum - c * x_k, k - 1]:
               # mark the coefficient of x_k to be c
               coeff[k-1] = c
               RecursivelyListAllThatWork(k - 1, sum - c * x_k)
               # unmark the coefficient of x_k
               coeff[k-1] = 0
    
    RecursivelyListAllThatWork(len(data), target_sum)
    

    Output

    10*1 +  0*2 +  0*4
     8*1 +  1*2 +  0*4
     6*1 +  2*2 +  0*4
     4*1 +  3*2 +  0*4
     2*1 +  4*2 +  0*4
     0*1 +  5*2 +  0*4
     6*1 +  0*2 +  1*4
     4*1 +  1*2 +  1*4
     2*1 +  2*2 +  1*4
     0*1 +  3*2 +  1*4
     2*1 +  0*2 +  2*4
     0*1 +  1*2 +  2*4
    

    【讨论】:

    • 非常感谢!有用!我试图将问题分解成部分并解决它,但我想我需要整个事情(我认为表格看起来会有所不同)。我会玩弄它,但看起来我可以在一台机器上运行表生成,然后让其他机器使用生成的表和 RecursivelyListAllThatWork 来扩展它。我会测试它,但非常感谢!
    【解决方案2】:

    你的代码是正确的

    1 = 1 * 1 + 0 * 2,所以 T[1, 2] 为真。

    1 = 1 * 1 + 0 * 2 + 0 * 4,所以 T[1, 3] 为真。

    根据 cmets 的要求,对算法进行简短说明: 它计算从 0 到 targetsum 的所有数字,这些数字可以表示为 data 中某些数字的(非负)倍数之和。 如果T[s, i]True,那么可以只使用data 的第一个i 元素来表示s。

    一开始,0可以表示为空和,因此T[0, 0]True。 (这一步可能看起来有点技术性。) 让x 成为数据的第 'i+1' 个元素。然后,该算法尝试每个数字s,如果它可以由x 的某个倍数和一个仅使用数据的第一个i 元素的表示存在的数字之和表示(存在这样的一个数字意味着T[s - c * x, i]True 对于某些c)。如果是这样,s 可以仅使用 data 的第一个 i+1 元素来表示。

    【讨论】:

    • 那我一定看不懂算法。我认为最后一个数字(在您的情况下为 2 和 3)表示要使用的变量在数据列表上的位置。只是为了澄清一下,这些数字是什么意思(我想我没有正确解释它们)?将 1 更改为 8 也会得到相同的结果..
    • 2(和 3)表示“您可以使用数据的前 2(或 3)个元素”,而不是“仅使用第 2(或 3)个元素”。
    【解决方案3】:

    附带说明一下,您实际上并不需要 defaultdict,您可以使用普通的 dict + .get()

    data = [1, 2, 4]
    target_sum = 10
    
    T = {}
    T[0, 0] = True
    
    for i,x in enumerate(data):
        for s in range(target_sum + 1):    # xrange on python-2.x
            for c in range(s // x + 1):
                if T.get((s - c * x, i)):
                    T[s, i+1] = True
    

    如果您使用的是 J.S.解决方案,别忘了改:

    if T[sum - c * x_k, k - 1]:
    

    与:

    if T.get((sum - c * x_k, k - 1)):
    

    【讨论】:

    • 谢谢,我试试看。只是想知道(我是 python 新手)最好避免导入您可以自己创建的函数还是导入更好?我想也许导入可能不利于内存使用,但制作库的人也可能提高了它的效率。我有点矛盾,所以不确定哪个更好。
    • @Lostsoul:不不,不要回避。如果您正在构建一个程序,您已经有很多事情要担心,如果其他人为您提供了可以帮助您的东西,请使用它!少担心一件事。他将是为你维护那件事的人。还要记住,过早的优化是(大多数)邪恶的根源。首先让事情开始工作,然后再看看你有性能/内存问题的地方。你可能想看看这个Perfomrance Tips
    猜你喜欢
    • 2015-02-21
    • 1970-01-01
    • 2013-12-12
    • 2012-03-26
    • 2013-11-27
    • 1970-01-01
    相关资源
    最近更新 更多