使用3个常量

时间:2015-10-24 12:14:11

标签: python algorithm math permutation combinatorics

因为我确定你们都知道“真正的甜甜圈店问题”(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))

解释

  • n =瓶数
  • k =包装箱数量,
  • K =一个箱子可以容纳的最大可装瓶数

每个箱子的K都不同,并且不需要是满的,甚至可以是空的。

所以,正如你所看到的,我正在计算它们有多少可能性,在X给定的Crates中给出X给定的瓶子,其中一个箱子最多可以容纳X瓶。

更好理解的示例: 可以说,我们有:

  • 7瓶(n)
  • 2 Crates (k) - > [k1,k2]
  • k1适合3瓶(K1),k2适合5瓶(K2) [k1 - > 3,k2 - > 5]

因此,他们 2 可以将瓶子放入板条箱内。

另一个:

  • 7瓶(n)
  • 3个板条箱(k) - > [k1,k2,k3]
  • k1适合2瓶,K2适合3瓶,K3适合4瓶

6 可能性

上面的代码计算完美,但是当我尝试使用时:

问题:

  • 30瓶(n)
  • 20 Crates(k)
  • k1 - > 1瓶(K1),k2 - > 2瓶(K2),k3 - > 3瓶(K3),k4 - > 4瓶(K4) ..等等,直到k20 - > 20瓶(K20),我相信你明白了......

它需要永远,所以我要求你;

问题:

我怎样才能改进上面的代码/功能?

1 个答案:

答案 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)存储为表的键的问题。