关于 斐波那契数列 的引申

最基本的函数模型是:

          /  0                             n=0
f(n)=      1                             n=1
          \ f(n-1)+(f-2)              n>1


1.我们一般的解法是:

int fun( int n )
{      
        if ( 0 == n )
        {
               return0;
        }
        elseif ( 1 == n )
        {
               return1;
        }
        else
        {
               returnfun(n - 1) + fun(n - 2);
        }
}



2.但是递归在大的数据的情况下可能超时( 特别是在OJ上的时候 )

那么我们想想还可以用:

#include <stdio.h>
 
int main()
{
   long long f[51] = { 0, 1 };
   long long n, a0 = 0, a1 = 1;
   int i;
 
   for( i = 2; i <= 50 ; i++ )
   {
            f[i] = a0 + a1;    // 此处只要遍历一次就ok
            a0 = a1;
            a1 = f[i];
   }
   while( scanf("%d", &n) != EOF )   // 我们可以得到任意的n的 Fibonacci 结果
   {
           printf("%lld\n", f[n]);
   }
   return 0;
}


3.算法导论上的Naive recursive squaring method 方法:其实也就是将其化成数学问题解决!

   Fibonacci的一条性质是:求N项的公式是有的,即:黄金比Q的N次方/根号5 即: pow( Q, N )/sqrt( 5 )
                                                   得到最近的一个整数,那么就是第N项的 Fibonacci 数值! ( Q = ( sqrt(5) + 1 ) / 2 是黄金比  )

   那么求前15项的代码如下:

    
#include <stdio.h>
#include <math.h>

int main()
{
    int i;
    double Q = 1.0 * ( 1 + sqrt( 5 ) ) / 2.0, t;
    
    for( i = 1; i < 15; i++ )
    {
         t = pow( Q, i )/sqrt(5);   // 取最近的整数就是第你项的fibonacci元素 
         
         if( (t - (int)t) < ( ( (int)t + 1 ) - t ) )  // 这个if是判断到底是那个整数近( 例如:1.3 离1近呢还是离2近 )
         { 
             printf("%d ", int(t));
         }
         else
         {
             printf("%d ", int(t) + 1);
         }
    }
    getchar();
    return 0;
}

实际我们知道,由于计算机的浮点数的位置限制,那么我们在做上面的算式时候,当N很大的时候,很多的位可能会丢失,那么所求的结果就是不准确的,所以理论上的意义会更大!实际编程时候,当N很大的时候实不可取的~

那么下面的办法就很重要了~

  

4.此处还要介绍一个非常好的办法:利用矩阵

Fibonacci 说白了就是一个递推序列,f( n ) = f( n - 1 ) + f( n - 2 );

变形一下有: f( n )  =  1 *f( n - 1 )  + 1 *  f( n - 2 );

那么使用矩阵表示就是:( 注意:下面表示的不好看,其实是矩阵表示,见谅! )

|  f( n )     |        |  1 1  |          |  f( n-1 ) |

|  f( n-1 )  |   =   |  1 0  |     *    |  f( n-2 )  |  

即:

|  f( n )     |     |  1 1  |                   |  f( 1 )  |

|  f( n-1 ) |  = |  1 0  | ^( n-1 )  *  |  f( 0 )  |

就是那个| 1 1 |

                | 1 0 |    的n-1次方后 乘以 初始化的两个数就是!


#include <stdio.h>
 
long long all[71];
 
void fun( int n )
{
    int i;
    long long mat[2][2] = { 1, 0, 0, 1 };      // 单位矩阵
    long long tmp[2][2];
   
    for( i = 2; i <= n; i++ )
    {
         tmp[0][0] = mat[0][0];
         tmp[0][1] = mat[0][1];
         tmp[1][0] = mat[1][0];
         tmp[1][1] = mat[1][1];
        
         mat[0][0] = tmp[0][0] + tmp[0][1];
         mat[0][1] = tmp[0][0];
         mat[1][0] = tmp[1][0] + tmp[1][1];
         mat[1][1] = tmp[1][0];
        
         all[i] = mat[0][0] * all[1] +mat[0][1] * all[0];
    }
}
 
int main()
{
    int n;
 
    all[0] = 0;
    all[1] = 1;
    fun( 70 );
 
    while( scanf("%d", &n) != EOF)
    {
           if( n == 0  )
           {
               printf("0\n");
           }
           else if( n == 1 )
          {
               printf("1\n");
           }
           else
           {
               printf("%lld\n",all[n]);
           }
    }
   
    return 0;
}


关于 Fibonacci  的变体:

1》青蛙跳台阶问题:

      一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

分析:

    当n =1, 只有1中跳法;当n =2时,有2种跳法;当n = 3 时,有3种跳法;当n = 4时,有5种跳法;当n = 5时,有8种跳法

    所以还是Fibonacci 序列,只不过初始化为:f(1) = 1; f(2) = 2;

#include <stdio.h>
 
long long all[71];
 
void fun( int n )
{
    int i;
    long long mat[2][2] = { 1, 0, 0, 1 };      // 单位矩阵
    long long tmp[2][2];
   
    for( i = 3; i <= n; i++ )
    {
         tmp[0][0] = mat[0][0];
         tmp[0][1] = mat[0][1];
         tmp[1][0] = mat[1][0];
         tmp[1][1] = mat[1][1];
        
         mat[0][0] = tmp[0][0] + tmp[0][1];
         mat[0][1] = tmp[0][0];
         mat[1][0] = tmp[1][0] + tmp[1][1];
         mat[1][1] = tmp[1][0];
        
         all[i] = mat[0][0] * all[2] +mat[0][1] * all[1];
    }
}
 
int main()
{
    int n;
 
    all[0] = 0;
    all[1] = 1;
    all[2] = 2;
    fun( 70 );
 
    while( scanf("%d", &n) != EOF)
    {
           if( n == 0 || n == 1 )
           {
               printf("1\n");
           }
           else
           {
               printf("%lld\n",all[n]);
           }
    }
   
    return 0;
}

或者代码为:

( 下面的代码计算大的数的时候可能超时,不建议 )

#include <stdio.h>
 
int count;
 
void fun( int s, int i, int n )
{    
      s += i;
     
      if( s == n )
      {
          count++;
          return;
      }
      else if( s > n )
      {
           return;
      }
      else        // 此处分叉
      {  
          fun( s, 1, n );  
          fun( s, 2, n );
      }
}
 
int main()
{
    int n;
   
    while( scanf("%d", &n) != EOF)
    {
           count = 0;
           fun( 0, 0, n );
          
           printf("%d\n", count);
    }
   
    return 0;
}


2》 跳台阶问题(变态跳台阶)

    一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法

分析:

 

             / 1                        n=1
f(n)=   2                             n=2
          \ f(n-1)+(f-2)            n>2

 
#include <stdio.h>
 
int main()
{
   long long f[51] = { 0, 1, 2 };
   long long n = 3, sum = 3;
   int i;
 
   for( i = 3; i <= 50 ; i++ )
   {
           f[i] = sum + 1;
           sum += f[i];
   }
 
   while( scanf("%d", &n) != EOF )
   {
          printf("%lld\n", f[n]);
   }
 
   return 0;
}


3》 矩形覆盖

      我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

分析:

      同上!( 说到底还是其变形 )


#include <iostream>
 using namespace std;
  
 int main()
 {
     long long f[71];
     int i;
     int n;
  
     f[0] = 1;
     f[1] = 1;
      
     for(  i = 2; i <= 70; i++ )
     {
         f[i] = f[i-1] + f[i-2];
     }
  
     while( cin >> n )
     {
         cout << f[n] << endl;
     }
     
     return 0;
 }



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值