裴波那契数列与应用

来源:互联网 发布:sql数据库设置 编辑:程序博客网 时间:2024/05/17 23:40

13世纪初,意大利数学家 裴波那契(Fibonacci) 在所著的《算盘书》中提出“兔子生崽”的趣题:

  • 假设兔子出生后两个月就能生小兔,且每月一次,每次不多不少恰好一对(一雌一雄),若开始时有初生的小兔一对,问一年后共有多少对兔子?

裴波那契数列是由这一“兔子生崽”问题引出的一个著名的递推数列,裴波那契数列的应用相当广泛,国际上已有许多关于裴波那契数列的专著与学术期刊,我国 周持中教授 所著的 《裴波那契——卢卡斯序列及其应用》 全面系统地研究了裴波那契与卢卡斯序列的理论及其在不定方程与数论上的应用;


裴波那契数列

裴波那契数列定义为:

  • f1=f2=1,fn=fn-1+fn-2 (n>2)

试求解裴波那契数列的第n项与前n项之和 (n从键盘输入);

1.递推设计求解:

(1)、设置一维数组f(k)存储数列的第k项,显然数列的递推关系为:

  • f(k)=f(k-1)+f(k-2) (k>2)

初始条件为:

  • f(1)=1,f(2)=1

从已知前两项这一初始条件出发,应用递推逐步推出第3项,第4项,……,以至堆出指定的第n项;

为实现求和,在k循环外给和变量s赋初值s=f(1)+f(2);在k循环内,每计算一项f(k),即累加到和变量s中:s=s+f(k)

(2)、递推程序设计:

#include<stdio.h>int main(){   int k,n;   long s,f[50];   printf("求F数列第n项与前n项和,请输入n:");   scanf("%d",&n);   f[1]=1;f[2]=1;            /*确定递推的初始值*/   s=f[1]+f[2];              /*和变量赋初值*/   for(k=3;k<=n;k++)   {      f[k]=f[k-1]+f[k-2];    /*实施递推*/      s+=f[k];               /*实施求和*/   }   printf("F数列第%d项为:%ld \n",n,f[n]);   printf("前%ld项之和为:%ld \n",n,s);}

2.迭代设计求解:

设数列从第1项开始为a,b,a,b,a,b,……,这里a,b为迭代变量;

(1)、循环前给a,b赋初值1,迭代和变量s赋初值a+b,这是迭代得基础;

(2)、设置条件为“k< n”的条件循环控制循环次数,循环中实施逐项迭代:实施“a=a+b;”迭代计算数列的下一项

借助c实现a、b互换,保持b是f数列的第k项;

实施“s=s+b;”迭代计算数列的和;

(3)、应用k控制迭代至k=n时结束;

#include<stdio.h>int main(){   int k,n;   long a,b,c,s;   printf("求F数列第n项与前n项和,请输入n:");   scanf("%d",&n);   a=1;b=1;s=a+b;            /*迭代变量a、b、s赋初值*/   k=2;   while(k<n)                /*控制迭代次数*/   {      k=k+1;                 /*迭代次数增1*/      a=a+b;                 /*推出的a是b的下一项*/      c=b;b=a;a=c;           /*借助c实现a、b互换,b是f数列的第k项*/      s=s+b;                 /*推出s是f数列的前k项之和*/   }   printf("F数列第%d项为:%ld \n",n,b);   printf("前%d项之和为:%ld \n",n,s);}

3.程序运行示例及其注意事项:

求F数列第n项与前n项和,请输入n:40F数列第40项为:102334155前40项之和为:267914295

F数列的第n项的值实际上就是第n个月时的兔子对数;

由以上递推设计与迭代设计可知,很多记数问题,应用递推可以求解,应用迭代也可以实现;

可以说迭代是简单形式的递推,而递推是迭代的引申与拓广;

比较递推设计与迭代设计,两者的时间复杂度是相同的,所不同的是,递推往往设置数组,而传统迭代设置简单迭代变量;

递推过程中数组元素带有下标,推出过程比传统迭代更为清晰;

正因为递推中应用了数组,因而保留了递推过程中的中间数据,例如以上求f数列的第40项后,数列的第20项保留在f(20)中,随时可以输出或查看;而传统迭代求解中并不保留迭代过程的中间数据;


条件素数序列

设正整数m、n满足条件:

  • (n^2 - mn - m^2)^2 = 1 (m<=n<=k)

其中指定正整数k(1<=k<=100000000000000)由键盘输入,若整数m+n为素数,则输出该素数并统计其个数;

例如,若k=2时,m=n=1满足条件,1+1=2为素数;m=1,n=2满足条件,1+2=3为素数,因而当k=2时有以上两个解;

1.设计要点:

这是一个条件序列的判别问题,可以采用以下方法求解:

(1)、在1~k的范围内设置二重循环枚举m,n,凡满足条件式的应用试商判别m+n是否为素数,这种求解方法简便易行,但当k较大时,枚举范围太大致使求解难以实现;

(2)、从题目中的条件式入手,寻求m,n的构成规律,从而简化求解操作;

显然,m=1,n=1满足题中的条件式,同时注意到:

  • (n^2 - mn - m^2)^2 = ((m+n)^2 - n(m+n) - n^2)^2

若m,n满足前一条件式,则n,(m+n)也满足上式,反之,若n,(m+n)满足上式,则m,n也满足前一条件式;

因而满足条件式的m,n按递增顺序排成一个最大项小于指定正整数k的裴波那契数列,即在裴波那契数列中找不出不大于指定数k的素数项;

从m=1,n=1开始求裴波那契数列,其中不大于指定数k的两项m,n,其对应的和t=m+n应用试商判别求素数,若t为素数,则输出并用s统计个数;

2.程序设计:

#include<stdio.h>#include<math.h>int main(){   double b,k,m,n,t;   int c,s,j;   printf("请输入正整数k:");   scanf("%lf",&k);   printf("m+n为以下素数: \n");   m=n=1;   s=0;   while(1)   {      t=m+n;      if(n>k)         break;      b=floor(sqrt(t));      c=0;      for(j=3;j<=b;j=j+2)         if(fmod(t,j)==0)          /*试商判别和t是否为素数*/         {            c=1;            break;         }      if(c==0 && fmod(t,2)>0 || t==2)      {         s++;         printf("%.0f ",t);      }      m=n;      n=t;                     /*迭代为下一个t做准备*/   }   printf("\n共有以上%d个素数\n",s);}

3.程序运行示例及其注意事项:

请输入正整数k:100000000000000m+n为以下素数:2 3 5 13 89 233 1597 28657 514229 433494437 2971215073共有以上11个素数

以上设计求解巧妙应用裴波那契数列简化了问题求解;

1 0