解析: 组合问题。题目的意思就是要求C(n,m).高中时学过
C (n,m) = n! / (m! * (n - m)!)
当然不能求出阶乘,只能逐步相乘,逐步约分,防止溢出。分子是从n - m + 1乘到n,分母是从1乘到m,都进行了m - 1次乘法!!
如果每一次消去他们的最大公约数,就也许能保证不溢出。
为了保证不超时,还需要优化,即 C (n,m) = C (n,n-m) 如果 n-m<m,应该令 m = n - m;
1 #include <stdio.h> 2 typedef long long llong; 3 llong gcd(llong m, llong n) /*求最大公约数*/ 4 { 5 llong temp; 6 if(n > m){ 7 temp = n; 8 n = m; 9 m = temp; 10 } 11 while(n != 0){ 12 temp = m % n; 13 m = n; 14 n = temp; 15 } 16 return m; 17 } 18 19 int main() 20 { 21 llong n, m; 22 llong i, j, fz, fm, temp; 23 while(scanf("%lld%lld", &n, &m) == 2 && n + m){ 24 fz = fm = 1; 25 if(n - m < m) 26 m = n - m; 27 for(i = 1, j = n; i <= m; i++, j--){ 28 fz *= j; 29 fm *= i; 30 temp = gcd(fz, fm); 31 fz /= temp; 32 fm /= temp; 33 } 34 printf("%lld\n", fz / fm); 35 } 36 return 0; 37 }
我们还学过一个公式 C(n,m)=C(n-1,m-1)+C(n-1,m) 但是一定会超时的。超时的代码如下:
1 //Time Limit 2 #include <stdio.h> 3 int C(int n, int m) 4 { 5 if(m == 0 || n == m) 6 return 1; 7 if(m == 1 || m == n - 1) 8 return n; 9 return C(n - 1, m - 1) + C(n - 1, m); 10 } 11 12 int main() 13 { 14 int n, m; 15 while(scanf("%d%d", &n, &m) == 2 && n + m) 16 printf("%d\n", C(n,m)); 17 return 0; 18 }