我在使用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,也许这就是我不确定的问题,但它是我试图去的思路,但它对我不起作用,因为它似乎打破了整体实施) 谢谢!
答案 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)
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]
,存在这样的数字意味着True
为c
。如果是这样,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)):