• 算法 —— 递推 ——五种典型的递推关系之Fabonacci数列


    在所有的递推关系中,斐波那契数列应该是最为熟悉的。

    在最基础的程序设计语言Logo语言中,就有很多这类的题目。

    而在较为复杂的Basic、Pascal、C语言中,斐波那契数列类的题目因为解法的相对容易一些,逐渐退出了竞赛的舞台。

    可是这不等于说斐波那契数列没有研究价值。

    Fabonacci数列常出现在比较简单的组合计数问题中。

    在优化法中,Fabonacci数列的用处也得到了较好的体现。

    兔子数列

    在这本书中,斐波那契提出了一个问题:

    在第一个月有一对刚出生的小兔子,在第二个月小兔子变成大兔子并开始怀孕,第三个月大兔子会生下一对小兔子,并且以后每个月都会生下一对小兔子。 如果每对兔子都经历这样的出生、成熟、生育的过程,并且兔子永远不死,那么兔子的总数是如何变化的?

    我们不妨先来看个图:
    在这里插入图片描述

    第一个月只有一对兔宝宝,1对兔子。

    第二个月兔宝宝变成大兔子,1对兔子。

    第三个月大兔子生了一对兔宝宝,一大一小2对兔子。

    第四个月大兔子继续生一对兔宝宝,小兔子变成大兔子。两大一小3对兔子。

    ….

    我们把这个数列列表

    在这里插入图片描述
    我们发现会发现以下几个规律:

    前一个月的大兔子对数就是下一个月的小兔子对数。
    前一个月的大兔子和小兔子对数的和就是下个月大兔子的对数。

    按照这个表格,我们会发现无论是小兔子对数、大兔子对数还是总对数,除了最初几个数字不一样之外,后面都是按照1、1、2、3、5、8、13…变化的,这个数列就称为兔子数列或者斐波那契数列。

    兔子数列最大的特点就是前两项之和等于后一项,比如1+1=2、1+2=3、2+3=5、3+5=8、5+8=13…

    我们用an表示一个数列的第n项,那么斐波那契数列的规律就是

    在这里插入图片描述
    这种式子称为递推式,也就是说可以从前面一项或几项,计算出后面一项的式子。再结合前两项a1=a2=1,就可以得到后面任意一项了。

    神奇的数列

    也许许多人觉得,斐波那契数列不过是浩如烟海的数学海洋中的一滴水。但是实际上,从这个数列被提出的那一天起,几百年来人们在许多领域都发现了它的影子。

    在数学上,许多求“方法数”的问题,答案都是斐波那契数列。例如:如果我们要上一个N级台阶的楼梯,每次只能走1格或者2格,那么一共有多少种走法呢?

    如果只有一级台阶,显然只有1种走法。

    如果有两级台阶,显然可以走一步,也可以走两步,因此有2种走法。

    如果有三级台阶,就有如图所示的3种走法。

    在这里插入图片描述
    1、2、3这三个数字都是斐波那契数。那么,如果有更多台阶怎么办呢?这就需要递推式了。

    由于一步最多走连两个台阶,因此要到达第N级台阶,有两种方案:

    走到第N-1级台阶上,然后走1级台阶跨到最上方;
    走到第N-2级台阶上,然后一步走两级台阶跨到最上方。

    注意,从第N-2级台阶走1级到N-1级台阶这种情况已经在第一种情况中计算过了。

    用a(N-1)和a(N-2)分别表示走到第N-1级和第N-2级台阶的方法数,那么走到第N级台阶的方法数就是:

    aN= a(N-1)+ a(N-2)

    显然,这就是斐波那契数列的递推公式,因此走台阶问题的解刚好是斐波那契数列。

    生活中最典型的斐波那契数列应用是在植物学中。
    在这里插入图片描述
    大树在生长的过程中会长出分枝,如果我们从下到上数分枝个数,就会发现依次是1、1、2、3、5、8、13…等等,刚好是斐波那契数列。

    有科学家对这种现象的解释是与兔子繁殖后代相同:每过一段时间老树枝都会萌发新芽,而新芽成长为成熟的树枝后也会每隔一段时间萌发一次新芽。

    另一个神奇的例子就是向日葵等植物。

    在这里插入图片描述
    如果我们仔细观察,就会发现向日葵盘内的种子形成两组螺旋线,一组是顺时针的,另一组是逆时针的。

    而这两组螺旋线的条数刚好是两个相邻的斐波那契数,小向日葵是34和55,大向日葵是144和233。

    松果种子、菜花表面也有类似的规律。
    在这里插入图片描述

    有科学家认为:这种排列可以使得种子的堆积最密集,最有利于植物繁衍后代。

    八百年来,人们在各个领域都发现了斐波那契数列。

    尤其是十九世纪开始,人们发现了斐波那契数列在计算机、物理、化学等领域的应用,这个古老的数列焕发了新的青春。

    1963年,斐波那契协会成立,并出版了《斐波那契季刊》用以刊登与斐波那契数列相关的研究成果。

    代码实现

    基本循环算法

    # include <iostream>
    # include <cstdio>
    using namespace std;
    int main(){
        int a=0,b=1,c=1,n;
        cin>>n;//输入n
        for(int i=3;i<=n;i++){
            a=b;
            b=c;
            c=a+b;
        }
        cout<<c; //输出最终结果 
        return 0;
    }
    

    递归算法实现

    # include <iostream>
    # include <cstdio>
    using namespace std;
    int f(int n){
        if(n==0) return 0;
        if(n==1) return 1;
        if(n>=2){
            return f(n-1)+f(n-2);
        }
    }
    int main(){
        int n;
        cin>>n;
        printf("%d",f(n));
        return 0;
    }
    

    递归算法优化(记忆化搜索)

    # include <iostream>
    # include <cstdio>
    # define MAX (101)
    using namespace std;
    int a[MAX];
    int f(int n){
        if(a[n]!=-1) return a[n];
        else{
            a[n]=f(n-1)+f(n-2);
            return a[n];
        }
    }
    int main(){
        int n;
        cin>>n;
        for(int i=0;i<=MAX-1;i++){        //初始化 
            a[i]=-1;
        }
        a[0]=0;a[1]=1;
        printf("%d",f(n));
        return 0;
    }
    

    高精度计算

    #include<iostream>
    #include<cstring>
    using namespace std;
    char sum[1200];
    int s=0,m=0,n;
    int main()
    {
     	cin>>n;
        string s1,s2;
        int a[1200],b[1200],he,i;
        s1="0";s2="1";
        for(m=2;m<n;m++)
        {
            memset(a,0,sizeof(a));
            memset(b,0,sizeof(b));
            a[0]=s1.length();
            for(i=1;i<=a[0];i++)
                a[i]=s1[a[0]-i]-'0';
            b[0]=s2.length();
            for(i=1;i<=b[0];i++)
                b[i]=s2[b[0]-i]-'0';
            he=(a[0]>b[0]?a[0]:b[0]);
            for(i=1;i<=he;i++)
            {
                a[i]+=b[i];
                a[i+1]+=a[i]/10;
                a[i]%=10;
            }
            he++;
            while((a[he]==0)&&(he>1))he--;
               for(i=he,s=0;i>=1;i--,s++)
                   sum[s]=a[i]+'0';
            s1=s2;
            s2=sum;
        }
        cout<<s2<<endl;
    	return 0;
    }
    
  • 相关阅读:
    Spring 系列目录
    Netty 源码 ChannelHandler(四)编解码技术
    Netty 源码 ChannelHandler(三)概述
    Netty 源码 Channel(二)核心类
    Netty 源码 Channel(二)主要类
    NOIP 2017 PJ
    初学 Size Balanced Tree(bzoj3224 tyvj1728 普通平衡树)
    一文读懂后缀自动机 Suffix_Automata
    完美字符子串 单调队列预处理+DP线段树优化
    棋盘覆盖 状压DP+矩阵快速幂
  • 原文地址:https://www.cnblogs.com/AlexKing007/p/12338927.html
Copyright © 2020-2023  润新知