斐波拉契数列=>多种方法的比较(分治、递归、动态规划/递推)

来源:互联网 发布:安卓原笔迹手写软件 编辑:程序博客网 时间:2024/04/28 21:52

斐波拉契数列是一个很不错的例子,它的第一项和第二项都为1,以后的每一项都是前两项的和。

这样,斐波拉契数列可以有很多种解法。

首先用递归:

//递归for斐波那契数列 #include<cstdio>#include<cstring>#include<iostream>#include<cmath>using namespace std;long long work(int n){if(n==1||n==2){return 1;}else{return work(n-1)+work(n-2);}}int main(){int n;//freopen("fei.in","r",stdin);//freopen("fei.out","w",stdout);scanf("%d",&n);printf("%lld",work(n));return 0;}
普通递归的方法存在很多的重复计算。效率自然很低。比如在算f(n-1)的时候,已经把f(n-2)算出来了,但是递归还要再算一次f(n-2)。

所以采用分治,一段一段计算,减少重复计算。

二分:

//二分分治for斐波那契 #include<cstdio>double n;int k;long long s,a;long long sishewuru(double g){if(g>=(int)g+0.5){return g+1;}else return g;}long long er(long long q){if(q==1||q==2){return 1;}else{return er(q-1)+er(q-2);}}long long wang(long long p){if(p==sishewuru(n/2)){return s;}if(p==sishewuru(n/2)-1){return a;}else return wang(p-1)+wang(p-2);}int main(){//freopen("fei.in","r",stdin);//freopen("fei.out","w",stdout);scanf("%lf",&n);s=er(sishewuru(n/2));a=er(sishewuru(n/2)-1);long long o=wang(n);printf("%lld",o);return 0;}
二分效率也是极其有限的,普通递归大概算到40左右已经是极限,而二分可以算到75左右。

所以进一步拆分问题,使他重复得更少。

三分:

//三分分治for斐波那契数列 #include<cstdio>double n;int k;long long s,a;long long f,d;long long sishewuru(double g){if(g>=(int)g+0.5){return g+1;}else return g;}long long er(long long q){if(q==1||q==2){return 1;}else{return er(q-1)+er(q-2);}}long long wang(long long p){if(p==sishewuru(n/3)){return s;}if(p==sishewuru(n/3)-1){return a;}else return wang(p-1)+wang(p-2);}long long ring(long long i){if(i==sishewuru(2*n/3)){return f;}if(i==sishewuru(2*n/3-1)){return d;}else return ring(i-1)+ring(i-2);}int main(){//freopen("fei.in","r",stdin);//freopen("fei.out","w",stdout);scanf("%lf",&n);s=er(sishewuru(n/3));a=er(sishewuru(n/3)-1);f=wang(sishewuru(2*n/3));d=wang(sishewuru(2*n/3)-1);long long o=ring(n);printf("%lld",o);return 0;}
三分已经可以在短时间内算出第110项左右了。接下来果断六分:

//六分分治for斐波那契数列 #include<cstdio>double n;int k;long long s,a;long long f,d;long long w,q,e,r,t,y;long long sishewuru(double g){if(g>=(int)g+0.5){return g+1;}else return g;}long long er(long long q){if(q==1||q==2){return 1;}else{return er(q-1)+er(q-2);}}long long wang(long long p){if(p==sishewuru(n/6)){return s;}if(p==sishewuru(n/6)-1){return a;}else return wang(p-1)+wang(p-2);}long long dao(long long x){if(x==sishewuru(n/3)){return f;}if(x==sishewuru(n/3-1)){return d;}else return dao(x-1)+dao(x-2);}long long yu(int v){if(v==sishewuru(n/2)){return w;}if(v==sishewuru(n/2-1)){return q;}else return yu(v-1)+yu(v-2);}long long nb(int m){if(m==sishewuru(2*n/3)){return r;}if(m==sishewuru(2*n/3-1)){return e;}else return nb(m-1)+nb(m-2);}long long ring(long long i){if(i==sishewuru(5*n/6)){return y;}if(i==sishewuru(5*n/6-1)){return t;}else return ring(i-1)+ring(i-2);}int main(){//freopen("fei.in","r",stdin);//freopen("fei.out","w",stdout);scanf("%lf",&n);s=er(sishewuru(n/6));a=er(sishewuru(n/6)-1);f=wang(sishewuru(n/3));d=wang(sishewuru(n/3)-1);w=dao(sishewuru(n/2));q=dao(sishewuru(n/2-1));r=yu(sishewuru(2*n/3));e=yu(sishewuru(2*n/3-1));y=nb(sishewuru(5*n/6));t=nb(sishewuru(5*n/6-1));long long o=ring(n);printf("%lld",o);return 0;}
六分经测,可以短时间内算出200项左右,也许可以到210项。

由此发现,普通的递归可以到40左右,二分到75左右,三分110左右,六分200左右,可以看出,可以在短时间内算到的项数(n)与它分成多少段(r)成正比。

大概以40左右为系数。即:n=k*r.

但是这样的方法也是极其有限的,想要计算到后面,就要不断地扩大分段,很是麻烦。

所以可以直接利用递推,用动态规划算出来,效率会大大增强。

//递推/动态规划for斐波那契 #include<cstdio>long long a[10000];int main(){int n;//freopen("fei.in","r",stdin);//freopen("fei.out","w",stdout);scanf("%d",&n);a[1]=a[2]=1;for(int i=3;i<=n;i++){a[i]=a[i-1]+a[i-2];}printf("%lld",a[n]);return 0;}
我定义了10000的整型数组,可以发现,这种方法计算10000项毫不费力。这样看来,这样的方法速度和效率都是非常高的。

斐波拉契数列 不同得解法还很多,这里不再列举。


1 0