初学acmer--读《算法竞赛入门经典》笔记(11)P61-65

来源:互联网 发布:网络七层协议 http 编辑:程序博客网 时间:2024/04/29 20:07

1.为什么main函数,我们总是让它返回0?

答:main函数作为整个程序的入口,有一个“其他的程序”来调用它--如操作系统、IDE、调试器、甚至自动评估系统。这个零表示“正常结束”,即返回给调用者。

在算法竞赛中,除了特殊要求以外,请总让它返回零,以免评估系统错误地认为程序异常退出了。

2.题目:计算组合数,编写一个函数,参数是两个非负整数n和m,返回组合数C_n^m=n!/m!*(n-m)!,其中m<=n<=25。例如,n=25,m=12时答案为5200300。

答案1:直接把公式表示出来。

long long factorial(int n) 
{
long long m=1;
for(int i=1;i<=n;i++)
{
m*=i;
}
return m;
}
long long fun(int n,int m)
{
   return factorial(n)/(factorial(m)*factorial(n-m));

但是当输入n=21,m=1的返回值竟然是-1!!可是答案明显是21啊。哪出问题了呢?通过结果是-1可以猜到可能是溢出了。但是明明已经用了long long了呀,仔细想想就会发现即使最终答案在所选择的数据类型范围之内,计算过程中的中间结果也可能会溢出。


答案二:可是如何避免中间结果溢出呢?办法就是“约分”。一个简单方法就是n!/m!=n*(n-1)...(m+2)*(m+1),虽然不能完全避免中间结果溢出,但是对于题目给出的范围已经可以保证得到正确的结果了。代码如下:

long long fun(int n,int m) 
{
if(m<n-m)  m=n-m;    //①
long long ans=1;
for(int i=m+1;i<=n;i++)  ans*=i;
for(int i=1;i<=n-m;i++)  ans/=i;
return ans;  
}


PS;①这句话的作用是在分母的m和n-m之中,找出大的那个,并用m来存,进行n!/m!的约分。


总结:对复杂的表达式进行化简有时不仅能减少计算量,还能减少甚至避免中间结果溢出。

3.①建议把谓词函数(用于判断某事物是否具有某种特性的函数)命名为“is_xxx”的形式,例如“is_prime”取自于“is it a prime”。

  ②在判断质数的函数中,会用到sqrt函数,值得注意的是,若直接写m=sqrt(n);  会存在一个问题,就是sqrt会将某个本应是整数的值变成了xxx.99999,也由于int型,强行被取整。解决方式可以是m=floor(sqrt(n)+0.5); 其中floor函数是取整函数。



阅读全文
0 0