您的位置:首页 > 其它

有关组合数越界的问题

2017-12-08 20:46 155 查看
最近周考做到这样一个题,本自信满满,却花费了大量时间也找不到bug在哪里。

题目内容:

n个人中选出k个人参加表演,求有多少种选法。

//我第一次的代码是这样
#include <stdio.h>
int fac(int n)
{
int f;
if(n==0) f=1;
else f=fac(n-1)*n;
return f;
}
int main()
{
// write your code here
int m,k,l;
int y;
scanf("%d%d",&m,&k);
l=m-k;
y=fac(m)/(fac(k)*fac(l));
printf("%d",y);
return 0;
}


看起来很好,但是实际上函数在多次递归可能越界了。于是我将int改为long long。由此可见,编写函数并不困难。写完之后的函数可以像cos、sqrt等库函数一样被调用。“别忘了测试!”如果你这样说,请为自己鼓掌。还记得那个“阶乘”之和的第一个程序吗?那个程序溢出了。那这个程序呢?很不幸:当m,k的值稍微大一点的时候,y的值竟然变成了-1。

即使最终答案在所选择的数据类型范围之内,计算的中间结果仍然可能溢出。

正确代码如下:

#include <stdio.h>
int compute(int n, int k)
{
if (k == 0)
{
return 1;
}
else
{
return (n * compute(n - 1, k - 1)) / k;
}
}
int main()
{
int m, n;
scanf("%d %d", &m, &n);
printf("%d\n", compute(m, n));
return 0;
}


这个题目还说明:即使认为题目在“暗示”你使用某种语言特性,也应该深入分析,不能贸然行事。如何避免中间结果溢出?办法是进行“约分”。一个简单的方法是利用n!/m!=(m+1)(m+2)…(n-1)n。虽然不能完全避免中间结果溢出,但是对于题目给出的范围已经可以保证得到正确的结果了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bug 组合数 递归 越界