计算大型组合

时间:2014-01-18 07:04:59

标签: c++ algorithm permutation dynamic-programming combinatorics

您如何计算组合,例如(100,000选择50,000)?

到目前为止,我尝试了三种不同的方法,但由于显而易见的原因,每种方法都失败了:

1)动态编程 - 数组的大小变得非常荒谬,它会出现故障

unsigned long long int grid[p+1][q+1];

//Initialise x boundary conditions
for (long int i = 0; i < q; ++i) {
  grid[p][i] = 1;
}

//Initialise y boundary conditions
for (long int i = 0; i < p; ++i) {
  grid[i][q] = 1;
}


for (long int i = p - 1; i >= 0; --i) {
  for (long int j = q - 1; j >= 0; --j) {
     grid[i][j] = grid[i+1][j] + grid[i][j+1];
   }
}

2)蛮力 - 显然计算甚至100!是不现实的

unsigned long long int factorial(long int n)
{
  return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
}

3)乘法公式 - 我无法存储它们太大的值

const int gridSize = 100000; //say 100,000
unsigned long long int paths = 1;

for (int i = 0; i < gridSize; i++) {
    paths *= (2 * gridSize) - i;
    paths /= i + 1;
}

// code from (http://www.mathblog.dk/project-euler-15/)

如果它对上下文有帮助,那么目的是解决大输入的“有多少路径存在m×n网格”问题。也许我错过了攻击这个问题?

3 个答案:

答案 0 :(得分:4)

C(100000,50000)是一个巨大的数字,包含30101个十进制数字:http://www.wolframalpha.com/input/?i=C%28100000%2C+50000%29

显然unsigned long long不足以存储它。你需要一些任意的大整数库,比如GMP:http://en.wikipedia.org/wiki/GNU_Multiple_Precision_Arithmetic_Library

否则,乘法公式应该足够好。

答案 1 :(得分:3)

“你如何计算...”在很大程度上取决于所需的准确度。精确的结果只能用任意的精确数字计算(例如GMP),但很可能你并不真正需要精确的结果。

在这种情况下,我会使用斯特林近似法求解因子(http://en.wikipedia.org/wiki/Stirling%27s_approximation)并用双精度计算。扩展中的加数可用于调节错误。维基百科页面也会给出错误估计值。

答案 2 :(得分:1)

这是一个可能有用的递归公式: -

NCk =(N-1)C(k-1)* N / K

首先使用递归调用(N-1)C(K-1),然后根据结果评估NCk。

由于您的数字非常大,请使用以下备选方案之一。

  
      
  1. GMP
  2.   
  3. 使用您自己的实现,您可以将数字存储为数组中的二进制位序列,并使用booth的算法进行乘法   和转移&amp;扣除除法。
  4.