计数有效地组合和排列 [英] counting combinations and permutations efficiently

查看:207
本文介绍了计数有效地组合和排列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些code来算排列组合,我试图使它更好地为大量涌现。

我已经找到了更好的算法排列,避免大的中间结果,但我仍然认为我可以做的更好的组合。

到目前为止,我已经把在特殊情况下,以反映无碳复写纸的对称性,但我还是想找到一个更好的算法,避免了调用阶乘(R),这是一个不必要的大中间结果。如果没有这种优化,最后文档测试时间过长尝试计算阶乘(99000)。

任何人都可以提出一个更有效的方法来计算组合?

 从数学进口阶乘

高清产品(迭代器):
    督促= 1
    对于n的迭代:
        督促* = N
    回刺

高清NPR(N,R):
    
    计算的ř物品从取有序排列的数目
    人口规模为n的。

    >>> NPR(3,2)
    6
    >>> NPR(100,20)
    1303995018204712451095685346159820800000
    
    断言0℃=为r = N
    返回的产物(范围(正 -  R + 1,N + 1))

高清NCR(N,R):
    
    计算的ř物品从取无序组合的数量
    人口规模为n的。

    >>> NCR(3,2)
    3
    >>> NCR(100,20)
    535983370403809682970
    >>> NCR(100000,1000)== NCR(100000,99000)
    真正
    
    断言0℃=为r = N
    在r> ñ// 2:
        R =正 -  R的
    返回NPR(N,R)//因子(R)
 

解决方案

如果n是不远处,则成为使用相结合的递归定义可能会更好,因为XC0 == 1,你只会有几个迭代:

这里的有关递归定义是:

= nCr的第(n-1)C(R-1)* N / R

这可以很好地利用尾递归与下面的列表计算:

[(正 - R,0),(正 - R + 1,1),(正 - R + 2,2),...,(正 - 1,R - 1),(N,R )]

这当然是在Python中很容易生成的 izip(的xrange(N(我们忽略,因为NC0 = 1的第一个条目)的 - R + 1,N + 1)的xrange(1,R + 1))注意,这里假设为r = N,你需要检查这一点,交换他们,如果他们不是。此外,优化的使用,如果为r N / 2,则R =正 - R

现在,我们只需要与减少使用尾递归应用递归一步。我们先从1自NC0为1,然后用从如下列表中的下一条目乘以电流值

 从itertools进口izip

减少(拉姆达的x,y:X * Y [0] / Y [1],izip(的xrange(正 -  R + 1,N + 1),的xrange(1,R + 1)),1)
 

I have some code to count permutations and combinations, and I'm trying to make it work better for large numbers.

I've found a better algorithm for permutations that avoids large intermediate results, but I still think I can do better for combinations.

So far, I've put in a special case to reflect the symmetry of nCr, but I'd still like to find a better algorithm that avoids the call to factorial(r), which is an unnecessarily large intermediate result. Without this optimization, the last doctest takes too long trying to calculate factorial(99000).

Can anyone suggest a more efficient way to count combinations?

from math import factorial

def product(iterable):
    prod = 1
    for n in iterable:
        prod *= n
    return prod

def npr(n, r):
    """
    Calculate the number of ordered permutations of r items taken from a
    population of size n.

    >>> npr(3, 2)
    6
    >>> npr(100, 20)
    1303995018204712451095685346159820800000
    """
    assert 0 <= r <= n
    return product(range(n - r + 1, n + 1))

def ncr(n, r):
    """
    Calculate the number of unordered combinations of r items taken from a
    population of size n.

    >>> ncr(3, 2)
    3
    >>> ncr(100, 20)
    535983370403809682970
    >>> ncr(100000, 1000) == ncr(100000, 99000)
    True
    """
    assert 0 <= r <= n
    if r > n // 2:
        r = n - r
    return npr(n, r) // factorial(r)

解决方案

if n is not far from r then using the recursive definition of combination is probably better, since xC0 == 1 you will only have a few iterations:

The relevant recursive definition here is:

nCr = (n-1)C(r-1) * n/r

This can be nicely computed using tail recursion with the following list:

[(n - r, 0), (n - r + 1, 1), (n - r + 2, 2), ..., (n - 1, r - 1), (n, r)]

which is of course easily generated in Python (we omit the first entry since nC0 = 1) by izip(xrange(n - r + 1, n+1), xrange(1, r+1)) Note that this assumes r <= n you need to check for that and swap them if they are not. Also to optimize use if r < n/2 then r = n - r.

Now we simply need to apply the recursion step using tail recursion with reduce. We start with 1 since nC0 is 1 and then multiply the current value with the next entry from the list as below.

from itertools import izip

reduce(lambda x, y: x * y[0] / y[1], izip(xrange(n - r + 1, n+1), xrange(1, r+1)), 1)

这篇关于计数有效地组合和排列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆