我编写了以下代码,用于使用涉及五边形数字的递推公式来评估整数分区:
def part(n):
p = 0
if n == 0:
p += 1
else:
k = 1
while ((n >= (k*(3*k-1)/2)) or (n >= (k*(3*k+1)/2))):
i = (k * (3*k-1)/2)
j = (k * (3*k+1)/2)
if ((n-i) >= 0):
p -= ((-1)**k) * part(n-i)
if ((n-j) >= 0):
p -= ((-1)**k) * part(n-j)
k += 1
return p
n = int(raw_input("Enter a number: "))
m = part(n)
print m
代码可以正常工作,直到n=29
。它在n=24
附近有点慢,但我仍然在一个不错的运行时内得到一个输出。我知道算法是正确的,因为产生的数字与已知值一致。
对于35以上的数字,即使等待很长时间(约30分钟),我也无法获得输出。我的印象是python可以处理比这里使用的数字大得多的数字。有人可以帮助我改善运行时间并获得更好的结果吗?此外,如果代码有问题,请告诉我。
答案 0 :(得分:3)
您可以使用Memoization:
def memo(f):
mem = {}
def wrap(x):
if x not in mem:
mem[x] = f(x)
return mem[x]
return wrap
@memo
def part(n):
p = 0
if n == 0:
p += 1
else:
k = 1
while (n >= (k * (3 * k - 1) // 2)) or (n >= (k * (3 * k + 1) // 2)):
i = (k * (3 * k - 1) // 2)
j = (k * (3 * k + 1) // 2)
if (n - i) >= 0:
p -= ((-1) ** k) * part(n - i)
if (n - j) >= 0:
p -= ((-1) ** k) * part(n - j)
k += 1
return p
演示:
In [9]: part(10)
Out[9]: 42
In [10]: part(20)
Out[10]: 627
In [11]: part(29)
Out[11]: 4565
In [12]: part(100)
Out[12]: 190569292
通过记忆我们记得以前的计算,所以对于重复计算,我们只是在dict中进行查找。
答案 1 :(得分:0)
你可以做很多事情。
删除重复的计算。 - 基本上你正在计算" 3 * k + 1"每次执行你的while循环很多次。您应该计算一次并将其分配给变量,然后使用该变量。
用更快的操作替换(-1)** k,如-2 *(k%2)+1)。因此,相对于k而言计算是线性的,它是常数。
缓存昂贵的确定性计算的结果。 "部分"是一种确定性的功能。它使用相同的参数多次调用。您可以构建映射到结果的输入的哈希映射。
考虑重构它以使用循环而不是递归。 Python不支持我理解的尾递归,因此当你使用深度递归时,必须保持非常大的堆栈。
如果你缓存计算,我可以保证它的运行速度要快很多倍。