整数分区的递归公式

时间:2015-12-22 17:58:02

标签: python recursion

我编写了以下代码,用于使用涉及五边形数字的递推公式来评估整数分区:

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可以处理比这里使用的数字大得多的数字。有人可以帮助我改善运行时间并获得更好的结果吗?此外,如果代码有问题,请告诉我。

2 个答案:

答案 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)

你可以做很多事情。

  1. 删除重复的计算。 - 基本上你正在计算" 3 * k + 1"每次执行你的while循环很多次。您应该计算一次并将其分配给变量,然后使用该变量。

  2. 用更快的操作替换(-1)** k,如-2 *(k%2)+1)。因此,相对于k而言计算是线性的,它是常数。

  3. 缓存昂贵的确定性计算的结果。 "部分"是一种确定性的功能。它使用相同的参数多次调用。您可以构建映射到结果的输入的哈希映射。

  4. 考虑重构它以使用循环而不是递归。 Python不支持我理解的尾递归,因此当你使用深度递归时,必须保持非常大的堆栈。

  5. 如果你缓存计算,我可以保证它的运行速度要快很多倍。