由于非常大的因子,无法计算组合数

时间:2015-12-09 15:37:22

标签: c# algorithm combinations factorial

我正在尝试计算某个数组中元素数量的组合数。我需要确切的组合数量才能将其用作GPU中要执行的线程数。

但数据非常大,并且无法根据任何数据类型计算该数字的阶乘。

有没有办法计算组合数而无需找到阶乘?或者更有效的方法呢?

总结了问题:

int no_of_combinations = combination(500,2);
public static int factorial(int m)
{
        int x = 1;

        for (int i = m; i > 0; i--)
            x = x * i;

        return x;
}
public static int combination(int m, int n)
{
    int x = 0;
    x = factorial(m) / (factorial(n) * factorial(m - n));
    return x;
}

4 个答案:

答案 0 :(得分:4)

在这种情况下,我会开始简化等式。在你的例子中,你正在寻找 500选择2 ,这是500!/ 498!/ 2!。这可以很容易地改为500 * 499/2,可以计算出来。

一般来说,如果你有 n选择k ,你只需要计算从 n max(k,nk)<的“部分因子” / em>然后除以 min(k,nk)!,因为镜像结果。这使计算更容易。

同样在某些情况下,您可以在乘以时开始用 min(k,n-k)!分割,但这会导致剩余等等。

答案 1 :(得分:3)

使用Pascal的三角形属性:

C(n,k)= C(n-1,k)+ C(n-1,k-1)和动态编程。没有涉及因子。

Pascal的三角形是:

        1
      1   1
    1   2   1
  1   3   3   1
1   4   6   4   1

答案 2 :(得分:2)

您不需要使用阶乘。如果k> n / 2,则使用C(n,k)= C(n,n-k)。然后使用C(n,0)= 1并且对于k> 0,C(n,k)= C(n,k-1)*(n-k + 1)/ k。这使得您可以计算与动态编程方法几乎一样多的二项式系数,但它需要线性时间(Theta(min(n-k,k)))和恒定空间而不是二次时间和线性空间。

查看过去的问题:How to efficiently calculate a row in pascal's triangle?

public static long combination(int n, int k)
{
  if (n-k < k)
    return combination(n,n-k);
  if (k < 0)
    return 0;
  long result = 1;
  for (int i=1; i<=k; i++)
  {
    result *= n-i+1;
    result /=i;
  } 
  return result;
}

如果答案时间n超过最大长度,则可能会溢出。所以,如果你希望答案适合32位int并且你有64位长,那么这不应该溢出。为避免溢出,请使用BigIntegers而不是long。

答案 3 :(得分:0)

你需要编写一个新函数,我们称之为FactorialMoverN

int FactorialMOverN(int m, int n)
{
    int x = 1;
        for (int i = m; i > n; i--)
            x = x * i;
    return x;
}

然后将组合功能更改为

x = FactorialMOverN(m,n) * factorial(m - n));

这应该有所帮助。如果它没有帮助,那么您需要使用不同的变量类型,或重新考虑您的问题。

感谢Sami,我可以看到上面的函数出错了。需要通过

计算500选择2
int MChooseN(int m, int n)
    {
        int x = 1;
            for (int i = m; i > (m-n); i--)
                x = x * i;
        return x;
    }

以上将需要500,2,并返回500 * 499,之前将需要500,2并返回500 * 499 * 498 ... 5 * 4 * 3这不是您想要的。

无论如何,以上是你能得到的最好的。