两个例题

一、计算组合数。编写函数,参数是两个非负整数n和m,返回组合数 ,其 中m≤n≤25。例如,n=25,m=12时答案为5200300。

【分析】 既然题目中的公式多次出现n!,将其作为一个函数编写是比较合理的:

long long factorial(int n){

  long long m = 1;

   for(int i = 1; i <= n; i++) m *= i;

   return m; }

long long C(int n, int m) {

  return factorial(n)/(factorial(m)*factorial(n-m)); }

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

当n=21,m=1的返回值是-1,溢出。

解决方法:约分。

一个简单的方法是利用n!/m!=(m+1) (m+2)…(n-1)n。虽然不能完全避免中间结果溢出,但是对于题目给出的范围已经可以保证得到正确的结果了。

long long C(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; }

小技巧:当m<n-m时把m变成n-m。作用:进一步降低复杂度。

二、素数判定。编写函数,参数是一个正整数n,如果它是素数,返回1,否则返回0。

【分析】 根据定义,被1和它自身整除的、大于1的整数称为素数。

//n=1或者n太大时请勿调用

int is_prime(int n) {

  for(int i = 2; i*i <= n; i++)

    if(n % i == 0) return 0;

return 1; }

小技巧:注意这里用到了两个小技巧。一是只判断不超过sqrt(x)的整数i。二 是及时退出:一旦发现x有一个大于1的因子,立刻返回0(假),只有最后才返回1(真)。 函数名的选取是有章可循的,“is_prime”取自英文“is it a prime?”(它是素数吗?)。

注意代码上方提示:太小是考虑 1 ,太大是考虑i*i会溢出。

改进版:

int is_prime(int n) {

  if(n <= 1) return 0;

  int m = floor(sqrt(n) + 0.5);

  for(int i = 2; i <= m; i++)

    if(n % i == 0) return 0;

return 1; }

除了特判n≤1的情况外,程序中还使用了变量m,一方面避免了每次重复计算sqrt(n),另 一方面也通过四舍五入避免了浮点误差——正如前面所说,如果sqrt将某个本应是整数的值 变成了xxx.99999,也将被修正,但若直接写m = sqrt(n),“.99999”会被直接截掉。

注:为什么只需要计算到开平方就可以?

https://blog.csdn.net/LZXloveGYD/article/details/71340090

原文地址:https://www.cnblogs.com/LOW-ctfer/p/10387617.html