我需要n!/(n-r)!r!
用 C# 计算。使用阶乘函数计算小数字很容易,但是当数字变得像 100 这样大时,它就不起作用了。有没有其他方法可以计算更大数字的组合?
4330 次
4 回答
17
首先,我注意到您正在尝试计算二项式系数,所以我们称之为。
这里有多种计算方法。如果您使用 BigInteger,则不必担心溢出:
方法一:使用阶乘:
static BigInteger Factorial(BigInteger n)
{
BigInteger f = 1;
for (BigInteger i = 2; i <= n; ++i)
f = f * i;
return f;
}
static BigInteger BinomialCoefficient(BigInteger n, BigInteger k)
{
return Factorial(n) / (Factorial(n-k) * Factorial(k));
}
方法二:使用递归:
static BigInteger BinomialCoefficient(BigInteger n, BigInteger k)
{
if (n == 0) return 1;
if (k == 0) return 0;
return BinomialCoefficient(n-1, k-1) + BinomialCoefficient(n-1, k)
}
但是,除非您记住结果,否则此方法并不快。
方法三:尽量减少乘法次数,提前除法。这使数字保持较小:
static BigInteger BinomialCoefficient(BigInteger n, BigInteger k)
{
// (n C k) and (n C (n-k)) are the same, so pick the smaller as k:
if (k > n - k) k = n - k;
BigInteger result = 1;
for (BigInteger i = 1; i <= k; ++i)
{
result *= n - k + i;
result /= i;
}
return result;
}
例如,如果您正在计算 (6 C 3),而不是计算 (6 x 5 x 4 x 3 x 2 x 1) / ((3 x 2 x 1) x (3 x 2 x 1)),您计算(((4 / 1) * 5) / 2) * 6) / 3,如果可能的话,保持数字很小。
于 2012-03-08T15:49:40.573 回答
5
按照 Eric 所说,早期划分有很大帮助,您可以通过从高到低划分来改善这一点。这样,只要最终结果适合 Long,您就可以计算任何结果。这是我使用的代码(为 Java 道歉,但转换应该很容易):
public static long binomialCoefficient(int n, int k) {
// take the lowest possible k to reduce computing using: n over k = n over (n-k)
k = java.lang.Math.min( k, n - k );
// holds the high number: fi. (1000 over 990) holds 991..1000
long highnumber[] = new long[k];
for (int i = 0; i < k; i++)
highnumber[i] = n - i; // the high number first order is important
// holds the dividers: fi. (1000 over 990) holds 2..10
int dividers[] = new int[k - 1];
for (int i = 0; i < k - 1; i++)
dividers[i] = k - i;
// for every divider there always exists a highnumber that can be divided by
// this, the number of highnumbers being a sequence that equals the number of
// dividers. Thus, the only trick needed is to divide in reverse order, so
// divide the highest divider first trying it on the highest highnumber first.
// That way you do not need to do any tricks with primes.
for (int divider: dividers)
for (int i = 0; i < k; i++)
if (highnumber[i] % divider == 0) {
highnumber[i] /= divider;
break;
}
// multiply remainder of highnumbers
long result = 1;
for (long high : highnumber)
result *= high;
return result;
}
于 2012-10-16T10:55:58.767 回答
0
对于 .net 4.0 和更大的使用类 BigInteger 而不是 int/long
对于其他 .net 使用自定义大数字类,例如来自 IntX: http: //www.codeplex.com/IntX/
于 2012-03-08T15:33:39.453 回答
0
我认为这将是有效
的它是 O(k)
注意!/r!r!只是取消了 n 的最后一个 r
所以 7 3
7 x 6 x 5 x 4 x 3 x 2 x 1
over
4 x 3 x 2 x 1
public static uint BinomialCoeffient(uint n, uint k)
{
if (k > n)
return 0;
uint c = n;
for (uint i = 1; i < k; i++)
{
c *= n - i;
c /= i + 1;
}
return c;
}
于 2017-08-08T22:11:02.060 回答