无法在python中实现动态编程表算法

时间:2012-02-09 23:46:35

标签: python algorithm dynamic-programming

我在使用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创建条目,即使它不存在,如果条目存在,算法将其变为true,也许这就是我不确定的问题,但它是我试图去的思路,但它对我不起作用,因为它似乎打破了整体实施) 谢谢!

3 个答案:

答案 0 :(得分:4)

如果您使用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

答案 1 :(得分:2)

您的代码正确

1 = 1 * 1 + 0 * 2,因此T [1,2]为真。

1 = 1 * 1 + 0 * 2 + 0 * 4,因此T [1,3]为真。

根据评论中的要求,对算法的简短解释: 它计算从0到targetsum的所有数字,可以表示为data中某些数字的(非负)倍数之和。 如果T[s, i]True,则可以仅使用i的第一个data元素以此方式表示s。

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

答案 2 :(得分:2)

作为旁注,您不需要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)):