我正在尝试计算某个数组中元素数量的组合数。我需要确切的组合数量才能将其用作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;
}
答案 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选择2int 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这不是您想要的。
无论如何,以上是你能得到的最好的。