組合數C(n, k)的求法:
1. 浮點數迭代法
缺點: 當數比較大的時候, 可能結構不夠精確.
使用公式
#include <iostream><br />using namespace std;<br />int main()<br />{<br />long double n, k, ans;<br />while(cin >> n >> k && (n || k)){<br />ans = 1;<br />if(k > n/2)<br />k = n - k;<br />for(long double i=0; i<k; i++)<br />ans *= (n-i)/(k-i);<br />cout.precision(0);<br />cout << fixed << ans << endl;<br />}<br />}
或:
#include <iostream><br />using namespace std;<br />__int64 c(__int64 n, __int64 k)<br />{<br />if(k == 0 || n==k)<br />return 1;<br />else<br />return c(n-1, k-1)*n/k;<br />}<br />int main()<br />{<br />__int64 n,k;<br />while (scanf("%I64d%I64d", &n, &k)!=EOF && (n+k))<br />{<br />if(2*k > n)<br />k = n-k;<br />printf("%I64d/n", c(n,k));<br />}<br />return 0;<br />}
2. 動態規劃法
缺點: 對空間有較大的要求.
具體為:
| n |
|
|
|
|
|
|
|
|
| 0 |
1 |
|
|
|
|
|
|
|
| 1 |
1 |
1 |
|
|
|
|
|
|
| 2 |
1 |
2 |
1 |
|
|
|
|
|
| 3 |
1 |
3 |
3 |
1 |
|
|
|
|
| 4 |
1 |
4 |
6 |
4 |
1 |
|
|
|
| 5 |
1 |
5 |
10 |
10 |
5 |
1 |
|
|
| 6 |
1 |
6 |
15 |
20 |
15 |
6 |
1 |
|
| 7 |
1 |
7 |
21 |
35 |
35 |
21 |
7 |
1 |
#define MAXSIZE 10000<br />long cnr(int n, int r)<br />{<br /> long c[MAXSIZE];<br /> int i, j;<br /> for (i = 0; i <= r; i++)<br /> c[i] = 1;<br /> for (i = 1; i <= n-r; i++)<br /> for (j = 1; j <= r; j++)<br /> c[j] += c[j-1];<br /> return c[r];<br />}
.快速演算法
還有一種快速演算法, 在<<C語言名題精選百則>>上有所敘述.
下面展示一道題:
pku 3219 Binomial Coefficients
求C(n, k)的最後一位是0,還是1(即結果是奇數還是偶數).
這道題採用一步一步的最佳化的示範方法.
可以注意到k<=n<2^31, k,n如此之大, 肯定不能用上面的方法, 也不必用, 因為他只需要知道結構是奇數還是偶數.
那判斷C(n,k) = A(n,k)/A(k,k)的分母分子個含有2這個因子的個數的多少,相減即可.
#include <iostream><br />using namespace std;<br />//方法一:<br />//利用c(n, k) = c(n-1,k-1)+c(n-1,k)的原始方法<br />//int c(int n, int k)<br />//{<br />//if(k==0 || n==k)<br />//return 1;<br />//else<br />//return (c(n-1,k-1)+c(n-1,k))&1;<br />//}<br />//奇(1)*奇(1)=奇(1), 偶(0)*奇(1)=偶(0), 偶(0)*偶(0)=偶(0) [求積為&]<br />//奇(1)+奇(1)=偶(0), 偶(0)+奇(1)=奇(1), 偶(0)+偶(0)=偶(0) [求和為^]<br />//方法二:<br />//利用c(n, k) = ∑c(k,i)*c(n-k, i) (i∈[0, k], 且n>=2*k)的快速求組合數演算法<br />//int c(int n, int k)<br />//{<br />//if(k == 0 || k == n)<br />//return 1;<br />//<br />//if(2*k > n)<br />//k = n-k;<br />//int ret = 1;<br />//for(int i = 1; i <= k; ++i)<br />//ret ^= c(k, i)&c(n-k, i);<br />//return ret;<br />//}<br />//方法三:<br />//利用C(n,k) = A(n,k)/A(k,k), 求分子和分母因子2的個數的方法.<br />int cal(int n)<br />{<br />int cnt = 0;<br />int c = 2;<br />while(n)<br />{<br />n >>= 1;<br />cnt += n;<br />}<br />return cnt;<br />}<br />int main()<br />{<br />unsigned int n, k;<br />while(scanf("%d%d", &n, &k) != EOF)<br />{<br />if(k == 0 || n == k)<br />{<br />printf("1/n");<br />continue;<br />}<br />if(2*k > n)<br />k = n-k;<br />int cnt1 = cal(n);<br />int cnt2 = cal(n-k);<br />int cnt3 = cal(k);<br />printf("%d/n", (cnt1-cnt2)>cnt3?0:1);<br />}<br />return 0;<br />}