Java 阶乘溢出引起的组合问题
我需要一个函数,可以计算的(n,k)的纸牌游戏 我当前的尝试是使用基于常用阶乘方法的函数:Java 阶乘溢出引起的组合问题,java,c#,math,Java,C#,Math,我需要一个函数,可以计算的(n,k)的纸牌游戏 我当前的尝试是使用基于常用阶乘方法的函数: static long Factorial(long n) { return n < 2 ? 1 : n * Factorial(n - 1); } static long Combinatory(long n , long k ) { return Factorial(n) / (Factorial(k) * Factor
static long Factorial(long n)
{
return n < 2 ? 1 : n * Factorial(n - 1);
}
static long Combinatory(long n , long k )
{
return Factorial(n) / (Factorial(k) * Factorial(n - k));
}
我知道这是因为当我做阶乘(52)时,我溢出了long,但是我需要的范围结果并不像看起来那么大
有没有办法克服这个问题 而不是使用默认的组合公式
n!/(k!x(n-k)!)
,使用组合函数的递归属性
(n, k) = (n - 1, k) + (n - 1, k - 1)
知道:(n,0)=1
和(n,n)=1
->这将使您避免使用阶乘和溢出您的long。
以下是您可以执行的实现示例:
static long Combinatory(long n, long k)
{
if (k == 0 || n == k )
return 1;
return Combinatory(n - 1, k) + Combinatory(n - 1, k - 1);
}
编辑:使用更快的迭代算法
static long Combinatory(long n, long k)
{
if (n - k < k)
k = n - k;
long res = 1;
for (int i = 1; i <= k; ++i)
{
res = (res * (n - i + 1)) / i;
}
return res;
}
静态长组合(长n,长k)
{
if(n-k
e、 g:
静态长组合(长n,长k)
{
返回(长)(阶乘(新的biginger(n))/(阶乘(新的biginger(k))*阶乘(新的biginger(n-k)));
}
静态BigInteger阶乘(BigInteger n)
{
返回n<2?1:n*阶乘(n-1);
}
您需要添加对System.Numerics
的引用才能使用BigInteger。如果这不是家庭作业,Apache的commons math包中有一个高效的实现
如果是家庭作业,开始在实现中避免阶乘
使用(n,k)=(n,n-k)的属性使用k的最大值重写选择
然后请注意,您可以将n!/k!(n-k)!减少到n*n-1*n-2..*k/(n-k)*(n-k-1)..*1表示将[k,n]中的每个数字相乘,然后除以[1,n-k]中的每个数字
// From memory, please verify correctness independently before trusting its use.
//
public long choose(n, k) {
long kPrime = Math.max(k, n-k);
long returnValue = 1;
for(i = kPrime; i <= n; i++) {
returnValue *= i;
}
for(i = 2; i <= n - kPrime; i++) {
returnValue /= i;
}
return returnValue;
}
//从内存中,请在信任其使用之前独立验证其正确性。
//
公共长选择(n,k){
长kPrime=数学最大值(k,n-k);
长返回值=1;
对于(i=kPrime;i递归公式也被称为,在我看来,这是计算组合数最简单的方法(对于0,你想计算二进制数。你为什么要用C#和Java来标记它?@p.s.w.g:因为这两种代码都是用Java和C#编译的,而且long都是64位的。我很好奇为什么你需要计算这么大的数字。近似值就足够了吗?这是非常低效的,而且他所说的数字,他可能仍然是他无法实际计算所需的值。这就像教科书上关于如何不使用递归的示例。@Servy,也是关于何时使用记忆的教科书示例。他还可以利用标识(n,k)=(n,n-k)是的,因为4!仍然不是一个很大的数字,但是当你到达8左右时,你就需要很长的时间,如果你能等很长一段时间,只需要几分钟。这就是O(N!)的问题所在算法。@jameslarge是的,这是一种可能的方法,可以使它不会执行得很糟糕。@Servy:我对答案进行了编辑。我希望它能让您满意,因为您的答案Java有一个BigInteger类,但它没有运算符重载,所以您需要调整/
,
static long Combinatory(long n, long k)
{
return (long)(Factorial(new BigInteger(n)) / (Factorial(new BigInteger(k)) * Factorial(new BigInteger(n - k))));
}
static BigInteger Factorial(BigInteger n)
{
return n < 2 ? 1 : n * Factorial(n - 1);
}
// From memory, please verify correctness independently before trusting its use.
//
public long choose(n, k) {
long kPrime = Math.max(k, n-k);
long returnValue = 1;
for(i = kPrime; i <= n; i++) {
returnValue *= i;
}
for(i = 2; i <= n - kPrime; i++) {
returnValue /= i;
}
return returnValue;
}
static int64_t* pascals_triangle( int N)
{
int n,k;
int64_t* C = calloc( N+1, sizeof *C);
for( n=0; n<=N; ++n)
{ C[n] = 1;
for( k=n-1; k>0; --k)
{ C[k] += C[k-1];
}
}
return C;
}