算法与数据结构数据结构与算法

斐波那契数列

2017-05-19  本文已影响26人  Chuck_Hu
前言

说实话写本文的时候Chuck心里是很虚的,因为数学是Chuck内心永远的伤。因为当初玩过ACM所以学了些数学相关的算法,斐波那契算法就是其中之一,然而现在这部分已经忘得差不多了。数学功底还不错的可以多看看,实在看不懂的话应该也不会有太大影响,在实际面试中尚未碰到有面试官问斐波那契数列的题。

正文

斐波那契数列都不陌生,该类型的题目在面试中被问到的几率不是很高,但其实现相对简单,在一些对数学有一定要求的企业可能会考到。其大致主要分为以下题型:
1.求具体某项的值(一般在45项以内,打表即可)
2.求具体某一项模K(通常是个大数项,一般采用矩阵法)
3.求斐波那契前几位数字(例如:HDU 的 3117 题)
4.求解 Fibonacci 的后多少位,这个和取模类似
5.求前n项和(矩阵法)

最常用最好用的——矩阵法

矩阵法涉及矩阵运算的实现,对于代码准确性有较高要求,且基于矩阵的斐波那契公式推导可以考验编程者的数学思维。

斐波那契数列

当所求项数很小的时候,一般采用打表法即逐项计算即可,但斐波那契数列增长迅速,对于一般的数列而言,到第50项时数字就已经非常之巨大,因此需要一种更高效的算法来求解。
以HIT OJ 2060为例

As we know , the Fibonacci numbers.Given two numbers a and b , calculate

Input
The input contains several test cases. Each test case consists of two non-negative integer numbers a and b (0 ≤ a ≤ b ≤1,000,000,000). Input is terminated by a = b = 0.
Output
For each test case, output S mod 1,000,000,000, since S may be quite large.
Sample Input
1 1
3 5
10 1000
0 0
Sample Output
1
16
496035733
题意:给定整数a,b求斐波那契数列第a项到第b项的和,对1,000,000,000取模

进行一波推导
s(n)=s(n-1)+F(n-1)+F(n-2)
{   0  , 1  , 0         {  F(0)           { F(1)
    1  , 1  , 0     x      F(1)       =     F(2)
    0  , 1  , 1 }          s(1)  }          s(2)  }   
以此类推
{   0  , 1  , 0     ^n-1           {  F(0)          {  F(n - 1)
    1  , 1  , 0                x      F(1)       =     F( n )
    0  , 1  , 1 }                     s(1)  }          s( n )  }  

不信可以自己推推看。
代码实现:

#include <iostream>
#define mod 1000000000
#define max 3
using namespace std;
typedef struct                 //建立3x3的矩阵
{
    long long m[max][max];
}matrix;
matrix p={0,1,0,       //按之前推导的定义矩阵p
          1,1,0,
          0,1,1};
matrix q={1,0,0,       //矩阵q为单位阵
          0,1,0,
          0,0,1};
matrix juzhenchengfa(matrix a,matrix b)        //矩阵乘法
{
    int i,j,k;
    matrix c;
    for(i=0;i<max;i++)
    {
        for(j=0;j<max;j++)
        {
            c.m[i][j]=0;
            for(k=0;k<max;k++)
            {
                c.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;
            }
            c.m[i][j]=(c.m[i][j]%mod+mod)%mod;
        }
    }
    return c;
}
//矩阵幂运算,数学不好的我选择背模版
matrix quickpow(long long n)
{
    matrix a=p,b=q;
    while(n>=1)
    {
        if(n&1) b=juzhenchengfa(a,b);
        n>>=1;
        a=juzhenchengfa(a,a);
    }
    return b;
}
int main()
{
    long long s,e,sum,sum1;
    matrix tmp,tmp1;
    while(cin>>s>>e)
    {
        if(s==0&&e==0) break;
        tmp=quickpow(e);
        sum=(tmp.m[2][0]+tmp.m[2][1]+2*tmp.m[2][2])%mod;
        tmp1=quickpow(s-1);
        sum1=(tmp1.m[2][0]+tmp1.m[2][1]+2*tmp1.m[2][2])%mod;
        cout<<(sum-sum1)%mod<<endl;
    }
}

其实斐波那契数列代码实现最难理解的就是quickpow()函数,对于奇数和偶数的处理略有不同,但代码量并不大,可以考虑背模版记忆。

例2:As we all known , the Fibonacci series : F(0) = 1, F(1) = 1, F(N) = F(N - 1) + F(N - 2) (N >= 2).Now we define another kind of Fibonacci : f(0) = 1 , f(1) = 1 , f(N) = X * f(N - 1) + Y * f(N - 2) (N >= 2).And we want to Calculate S(N) , S(N) = f(0)2 +f(1)2+……+f(n)2.
Input :There are several test cases. Each test case will contain three integers , N, X , Y, N(2<= N <= 2^31 – 1 X : 2<= X <= 2^31– 1 Y : 2<= Y <= 2^31 – 1 )
Output :For each test case , output the answer of S(n).If the answer is too big , divide it by 10007 and give me the reminder.
其实就是斐波那契公式发生了点变化,这种情况下只需要对原有矩阵进行修改即可:

 { 1 ,  1 ,   0 ,   0,           { s(n-1)             { s(n)           {            s(n-1)+f^2(n-1)
   0 , x^2 , y^2 , 2*x*y,          f^2(n-1)             f^2(n)           x^2*f^2(n-1)+2*x*y*f(n-1)*f(n-2)+y^2*f^2(n-2)
   0 ,  1 ,   0,    0,       x     f^2(n-2)       =     f^2(n-1)    =                   f^2(n-1)
   0 , x^2 ,  0 ,   y    }       f(n-1)*f(n-2)  }     f(n)*f(n-1)}               x^2*f(n-1)+y*f(n-1)*f(n-2)        }
#include <iostream>
#include <stdio.h>
#include <cstring>
#define Mod 10007
using namespace std;
const int MAX = 4;
typedef  struct
{
    int  m[MAX][MAX];
}  Matrix;
Matrix P={1,1,0,0,
          0,0,0,0,
          0,1,0,0,
          0,0,0,0};
Matrix I={1,0,0,0,
          0,1,0,0,
          0,0,1,0,
          0,0,0,1};
Matrix matrixmul(Matrix a,Matrix b) //矩阵乘法
{
    int i,j,k;
    Matrix c;
    for (i = 0 ; i < MAX; i++)
        for (j = 0; j < MAX;j++)
        {
            c.m[i][j] = 0;
            for (k = 0; k < MAX; k++)
            c.m[i][j] += (a.m[i][k]* b.m[k][j])%Mod;
            c.m[i][j] %= Mod;
        }
    return c;
}
Matrix quickpow(long long n)
{
    Matrix m = P, b = I;
    while (n >= 1)
    {
        if (n & 1)
        b = matrixmul(b,m);
        n = n >> 1;
        m = matrixmul(m,m);
    }
    return b;
}
int main()
{     int n,x,y,sum;
      Matrix b;
      while(cin>>n>>x>>y)
      {
          sum=0;
          x=x%Mod;
          y=y%Mod;
          P.m[1][1]=(x*x)%Mod;
          P.m[1][2]=(y*y)%Mod;
          P.m[1][3]=(2*x*y)%Mod;
          P.m[3][1]=x;
          P.m[3][3]=y;
          b=quickpow(n);
          for(int i=0;i<4;i++)
            sum+=b.m[0][i]%Mod;
          cout<<sum%Mod<<endl;
      }
return 0;
}
上一篇下一篇

猜你喜欢

热点阅读