因为我确定你们都知道“真正的甜甜圈店问题”(https://math.stackexchange.com/questions/223345/counting-donuts)。所以我开始......
我有3个整数,这三个都是由用户输入的。与他们一起,我需要计算他们有多少可能的排列。我已经有了一些代码,它适用于小整数,如果它们变大,我的工具运行几天/小时?
用于计算可能排列的递归函数:
def T(n, k, K):
if k==0: return n==0
return sum(T(n-i, k-1, K) for i in xrange(0, K[k-1]+1))
解释
每个箱子的K都不同,并且不需要是满的,甚至可以是空的。
所以,正如你所看到的,我正在计算它们有多少可能性,在X给定的Crates中给出X给定的瓶子,其中一个箱子最多可以容纳X瓶。
更好理解的示例: 可以说,我们有:
因此,他们 2 可以将瓶子放入板条箱内。
另一个:
6 可能性
上面的代码计算完美,但是当我尝试使用时:
问题:
它需要永远,所以我要求你;
问题:
我怎样才能改进上面的代码/功能?
答案 0 :(得分:1)
您的问题是计算次数的指数式爆炸。但是这些计算反复计算同样的事情。
解决方案是存储中间值AKA memoization。
这是python 3.2中的一个版本,使用functools.lru_cache为你做备忘录
import functools
def T(n, k, K):
@functools.lru_cache(maxsize=None)
def Tsub(n,k):
if k==0: return n==0
return sum(Tsub(n-i,k-1) for i in range(0, K[k-1]+1))
return Tsub(n,k)
print( T(7,2,[3,5]) )
print( T(7,3,[2,3,4]) )
print( T(30,20,list(range(20))) )
在我的机器上,最终结果是2172723680407,并立即获得。
如果您没有python 3.2,可以这样做:
def T(n, k, K):
cache = {}
def Tsub(n,k):
key = (n,k)
if key in cache:
return cache[key]
if k==0:
cache[key] = (n==0)
return n==0
v = sum(Tsub(n-i,k-1) for i in xrange(0, K[k-1]+1))
cache[key] = v
return v
return Tsub(n,k)
print( T(7,2,[3,5]) )
print( T(7,3,[2,3,4]) )
print( T(30,20,list(range(20))) )
函数的奇怪嵌套用于解决您无法将列表(K
)存储为表的键的问题。