在 Python 中仅使用一次数字的整数分区递归很慢

Max*_*Max 2 python algorithm recursion python-2.7

我正在尝试使用 Python 2.7 中的每个数字计算可能组合的数量,以添加到单个值。

例如,对于 7,这将是 6+1、5+2、4+3、4+2+1 --> 4 种可能的组合

我设法将它伪造成一个递归函数,它可以正确地进行数学运算

import time

counter_list = []

def start(n):
    tic=time.time()
    recursive_step(range(1, n), n)
    toc=time.time()
    print(toc - tic)
    return len(counter_list)

def recursive_step(numbers, target, summe=0):

    if summe == target:
        counter_list.append(1)
    if summe >= target:
        return

    for i in xrange(len(numbers)):
        n = numbers[i]
        remaining = numbers[i+1:]
        recursive_step(remaining, target, summe + n)

if __name__ == "__main__":
    print(start(7))
Run Code Online (Sandbox Code Playgroud)

不幸的是,当数字变大时,它变得非常慢。以下是我在我的机器上测量的一些数字。

~~~ 40 ~~~
time in seconds:        0.0789999961853
possible combinations:  1112
~~~ 50 ~~~
time in seconds:        0.40299987793
possible combinations:  3657
~~~ 60 ~~~
time in seconds:        1.51200008392
possible combinations:  10879
~~~ 70 ~~~
time in seconds:        5.41400003433
possible combinations:  29926
~~~ 80 ~~~
time in seconds:        18.388999939
possible combinations:  77311
~~~ 90 ~~~
time in seconds:        54.5920000076
possible combinations:  189585
Run Code Online (Sandbox Code Playgroud)

我研究了动态编程原则。但我无法让它解决这个问题。任何关于我如何改进该脚本的建议将不胜感激

Pau*_*kin 5

关于此序列的参考:http : //oeis.org/A000009

您可以将分割n成不同部分的问题视为硬币兑换问题,其中(单个)硬币的价值为 1 到 n。(或者比这少一个,因为您似乎不允许将 of 划分n为单个数字n)。

您可以通过调整标准的硬币变化动态规划解决方案来计算解决方案。

def Q(n):
    A = [1] + [0] * n
    for i in range(1, n+1):
        for j in range(n, i-1, -1):
            A[j] += A[j-i]
    return A[n] - 1

print(Q(500))
Run Code Online (Sandbox Code Playgroud)

您可以通过注意到k在外循环的迭代之后,A[i]包含i使用来自 的不同元素进行分区的方式数来理解该程序1..k。而这的划分方式的数量i与不同的元素1..k+1是分区的方式的数量i与不同的元素1..k加的划分方式的数量i-k-1与元素1..k

这在 O(n^2) 时间内运行,但对于小案例来说速度很快(例如:这里的分区为 500,在我的机器上需要 0.033 秒)。