求一個組合數Cnm的值,Cnm= n! /(n-m)!*m!化簡的結果為
Cnm = (n*(n-1)*…*(n-m+1))/m!
這個直接求根據公式直接求顯然是不行的,當n和m較大時,顯然是要溢出的。目前知道兩種解決這種題的思路:
思路一:可以利用遞推關系式Cnm = C(n)(m-1) + C(n-1)(m-1)來實現,這樣初始化前幾個組合數,在根據題目要求處理的最大n和m值,遞推求出所有的Cnm,並保存。
實現方法以后補上。
思路二:為了避免直接計算n的階乘,可以直接對公式兩邊取對數,於是得到:ln(C(n,m)) = ln(n!) - ln(m!) - ln( (n-m)! )
對數有性質:ln(x*y) = ln(x) + ln(y),因此轉化成:
Ln(n!) = ln(1) + ln(2) + …+ln(n);
同理消去重疊的部分得到:
Cnm = (n*(n-1)*…*(n-m+1))/m!
因此這個算法時間復雜度仍然是 O( m ),雖然浮點計算比整數計算要慢,但解決了整數計算的溢出問題。
代碼實現(轉)
double cnm_lg(int n,int m)
{
int i;
double s1=0.0,s2=0.0;
for(i=1;i<=m;i++)
s1 += log(i);
for(i=n-m+1;i<=n;i++)
s2 += log(i);
return s2-s1;
}
double cnm_double(int n,int m)
{
if(m > n/2)
m = n-m;
return exp(cnm_lg(n,m));
}