问题描述:
已知:给定正整数N和M(5 ≤ M ≤ N ≤ 100)
求:组合C(M, N),即N! / ((N-M)!·M!)
输入:若干组case,每组case占用1行,包含两个正整数N和M,0 0表示输入结束
输出:对应的C(M, N)值,并按如下格式输出:[N] things taken [M] at a time is [C(M, N)] exactly.
Sample Input:
100 6
20 5
18 6
0 0
Sample Output:
100 things taken 6 at a time is 1192052400 exactly.
20 things taken 5 at a time is 15504 exactly.
18 things taken 6 at a time is 18564 exactly.
思路:
C(M, N)可化简为A(N-M+1, N) / M!,即N·(N-1)·...·(N-M+1) / (M·...·2·1),因此本题实际考察高精度数 × 普通整数和高精度数 ÷ 普通整数两种操作。其中乘法较简单,见《高精度运算总结》;除法较复杂,见《poj 1220(高精度数的任意进制转换)》
代码:
#include <stdio.h>
int a[200];
int size = 0, cur, last; //size保存高精度数当前的位数
void mul(int b){ //高精度乘法,b为乘数
int cf = 0;
for(int i = 0; i < 200; i++){ //循环尽头必须为数组大小200,而不能为size或size+1
a[i] = a[i]*b+cf;
cf = a[i]/10;
a[i] %= 10;
}
for(int i = size; i < 200; i++) //更新size
if(a[i] != 0) size++;
}
void div(int b){ //高精度除法
last = 0;
int i;
for(i = size-1; i >= 0; i--){
cur = last*10+a[i];
if(cur < b){
a[i] = 0; //原地将商保存在被除数数组a中
last = cur;
}
else{
a[i] = cur/b;
last = cur%b;
}
}
for(i = size-1; i >= 0; i--) //更新size
if(a[i] != 0) break;
size = i+1;
}
int main(){
int n, m;
while(1){
scanf("%d%d", &n, &m);
if(n == 0 && m == 0) break;
for(int i = 0; i < 200; i++)
a[i] = 0;
a[0] = size = 1; //初始化a和size
for(int i = n-m+1; i <= n; i++) mul(i);
for(int i = 2; i <= m; i++) div(i);
printf("%d things taken %d at a time is ", n, m);
for(int i = size-1; i >= 0; i--)
printf("%d", a[i]);
printf(" exactly.\n");
}
return 0;
}