我正在解决一个编程问题,该问题在高效计算nCr
时遇到困难,同时避免溢出。我做了以下简单的简化,但我很好奇是否有更复杂的简化可用。
(n)!/(n-k)!*k! = n*(n-1)*.....*(max(n-k+1, k))/(min(n-k, k-1))
考虑到k为偶数或奇数的不同情况,可以有更多的简化,只是建议一种方法。
任何评论都表示赞赏。
答案 0 :(得分:5)
我在这里找到了一个有趣的解决方案:http://blog.plover.com/math/choose.html
unsigned choose(unsigned n, unsigned k) {
unsigned r = 1;
unsigned d;
if (k > n) return 0;
for (d=1; d <= k; d++) {
r *= n--;
r /= d;
}
return r;
}
这可以通过交替执行乘法和除法来避免溢出(或至少限制问题)。
E.g。对于n = 8
,k = 4
:
result = 1;
result *= 8;
result /= 1;
result *= 7;
result /= 2;
result *= 6;
result /= 3;
result *= 5;
result /= 4;
done
答案 1 :(得分:0)
我也必须解决这个问题。我所做的是使用与除法相同的乘法次数并将它们捆绑在一起的事实,一次取一次乘法和一次除法。它在结尾处以整数形式出现,但我使用double作为中间项,然后舍入到最后的最接近的整数。
// Return the number of combinations of 'n choose k'
unsigned int binomial(unsigned int n, unsigned int k) {
unsigned int higher_idx;
unsigned int lower_idx;
if(k > n-k) {
higher_idx = k;
lower_idx = n - k;
} else {
higher_idx = n - k;
lower_idx = k;
}
double product = 1.0;
double factor;
unsigned int idx;
for(idx=n; idx>higher_idx; idx--) {
factor = (double)idx / double(lower_idx - (n - idx));
product *= factor;
}
return (unsigned int)(product + 0.5);
}