轉 組合數快速演算法!!!

2022-02-14 12:23:53 字數 1813 閱讀 8383

計算組合數最大的困難在於資料的溢位,對於大於150的整數n求階乘很容易超出double型別的範圍,那麼當c(n,m)中的n=200時,直接用組合公式計算基本就無望了。另外乙個難點就是效率。

對於第乙個資料溢位的問題,可以這樣解決。因為組合數公式為:

c(n,m) = n!/(m!(n-m)!)

為了避免直接計算n的階乘,對公式兩邊取對數,於是得到:

ln(c(n,m)) = ln(n!)-ln(m!)-ln((n-m)!)

進一步化簡得到:

這樣我們就把連乘轉換為了連加,因為ln(n)總是很小的,所以上式很難出現資料溢位。

為了解決第二個效率的問題,我們對上式再做一步化簡。上式已經把連乘法變成了求和的線性運算,也就是說,上式已經極大地簡化了計算的複雜度,但是還可以進一步優化。從上式中,我們很容易看出右邊的3項必然存在重複的部分。現在我們把右邊第一項拆成兩部分:

這樣,上式右邊第一項就可以被抵消掉,於是得到:

上式直接減少了2m次對數計算及求和運算。但是這個公式還可以優化。對於上面公式裡的求和,當mn/2時,n-m就會小很多。我們知道:

c(n,m) = c(n,n-m)

那麼通過這個公式,我們可以把小於n/2的m變為大於n/2的n-m再進行計算,結果是一樣的,但是卻能減少計算量。

當計算出ln(c(n,m))後,只需要取自然對數,就可以得到組合數:

c(n,m) = exp(ln(c(n,m)))

這樣就完成了組合數的計算。

用這種方法計算組合數,如果只計算ln(c(n,m))的話,n可以取到整型資料的極限值65535,

ln(c(65535,32767)) = 45419.6

而計算時間只需要0.01ms。當然,如果要取對數得到最終的組合數的話,n的取值就不能達到這麼大了。但是這種演算法仍然可以保證n取到1000以上,而不是開頭說的150這個極限值。例如:

c(1000,500) = 2.70288e+299

計算時間仍然小於0.01ms。

採用我這種演算法,不僅n的取值範圍大,而且計算速度高,不像用遞迴演算法實現這個問題的時候,很容易陷入遞迴層次太深而導致計算時間太長。

演算法**實現如下:

1 double lnchoose(int n, int m)

2 7     if (m < n/2.0)

8    

11     double s1 = 0;

12     for (int i=m+1; i<=n; i++)

13    

16     double s2 = 0;

17     int ub = n-m;

18     for (int i=2; i<=ub; i++)

19    

22     return s1-s2;

23 }

2425 double choose(int n, int m)

26 31     return exp(lnchoose(n, m));

32 }

//c(n,m)=c(n-1,m-1)+c(n-1,m)

1 #include 2 #include 3

4using

namespace

std;56

double c(int m,intn)7

14for(int i=2;i<=n;i++)

1518

for(int i=2;i<=n-m;i++)

1922

23//

cout<24

25return sb-sa-sc;26}

2728

intmain()

29

iOS 快速演算法

設要排序的陣列是mutablearray物件,首先任意選取乙個資料 通常選用陣列的第乙個數 作為關鍵資料,然後將所有比它小的數都放到它前面,所有比它大的數都放到它後面,這個過程稱為一次快速排序。步驟講解 1 設定兩個變數i,j,排序開始時i 0,就j mutablearray.count 1 2 設...

組合數演算法

什麼是組合數呢?從m個不同元素中取出n n m 個元素的所有組合的個數,叫做從m個不同元素中取出n個元素的組合數 combination 組合數基本公式為 cn m m n m n 線性寫法為 c m,n m m n n 現實生活中彩票的概率計算就涉及到組合數,比如雙色球中紅球選擇需要從01 33紅...

均值濾波快速演算法

1 概述 在影象處理中,在進行如邊緣檢測這樣的進一步處理之前,通常需要首先進行一定程度的降噪。中值濾波是一種非線性數字濾波器技術,經常用於去除影象或者其它訊號中的雜訊。這個設計思想就是 檢查輸入訊號中的取樣並判斷它是否代表了訊號,使用奇數個取樣 組成的觀察窗實現這項功能。觀察窗口中的數值進行 排序,...