カメヲラボ

主にプログラミングとお勉強全般について書いてます

コンビネーションの計算

http://acm.pku.edu.cn/JudgeOnline/problem?id=1306
http://acm.pku.edu.cn/JudgeOnline/problem?id=2249
これらは単にnCrを計算するだけの問題なのだが、ただ公式通りにやろうとすると簡単にオーバフローしてしまう。何も考えずにやりたければJavaで書くのが楽だろう。しかしなるべく桁数を抑えながら、しかも簡単に計算する方法はないか。

というわけで、昨日いろいろと考えたのだがこんなコードが通った。


double ans;
int k,n,r;

main(){

for( ; scanf("%d%d",&n,&r) == 2; )
{
if( (n+r) == 0 ) break;// n=r=0で終了

ans = 1;
// rが大きいときはn-rにして計算回数を減らす
r = (r>n/2)? n-r: r;

for( k = 1; k <= r; )
{
ans = ans*n/k;// ans*=n/kはダメ
--n;
++k;
}

// あってる
printf("%.lf\n", ans);
}

}

桁数が少なくなるように計算するためには分母・分子の掛け算をしつつ約分ができれば良いわけだが、たとえばn=9, r=4で計算するとすれば、

上記のように左から1列、2列…と見ると必ず約分できる。ということはループのたびに確実に約分ができて、しかもそれは自然数になるので超簡単に計算が出来る。短いコードを書くにはこの方法がベストかなぁと思うのだけど、もっと良い方法があるんだろか・・・。ロベールさんid:Robeがさらりと超短いコードを通してらっしゃるけど、同じ方法なのかな??