VJ水题堆-关于斐波那契数列的求解过程

做水题的过程中,有很多题一看就知道是与斐波那契数列相关知识求解的过程,即a[x]=a[x-1]+a[x-2];
例如:

1.超级楼梯:
有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法? 
输入数据首先包含一个整数N,表示测试实例的个数,然后是N行数据,每行包含一个整数M(1<=M<=40),表示楼梯的级数。
对于每个测试实例,请输出不同走法的数量。

2.一只小蜜蜂... 
有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行。请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数。 

其中,蜂房的结构如下所示。

一只小蜜蜂原题

3.骨牌铺方格 
在2×n的一个长方形方格中,用一个1× 2的骨牌铺满方格,输入n ,输出铺放方案的总数. 

例如n=3时,为2× 3方格,骨牌的铺放方案有三种,如下图

骨牌铺方格原题

很容易发现这些题都是利用斐波那契数列直接求解的题。或者抽象一点,都是通过递归方法进行求解。谈及递归很容易想到的是利用函数的递归调用进行求解。比如说:

int fun(int x)
{
    if(x==1||x==0)return 1;
    return fun(x-1)+(x-2);
}

这样的解法直接明了,但是在提交过程中总发现会TE。仔细分析发现是对于每次运算的结果没有进行储存而造成了重复运算。比如在计算fun(40)时递归计算了fun(39)和fun(38),而在计算fun(39)的过程中又计算了一遍fun(38)。也就是说,计算过一遍的结果不能加以储存,重复的计算造成了时间上的浪费。
这时候很容易想到用数组来储存对应的结果。那么为了实现递归数列的计算,应该这样操作

int a[55];
a[0]=a[1]=1;
for(int i=2;i<55;i++)
    a[i]=a[i-1]+a[i-2];

此时数组中储存的就应该是斐波那契数列的第n项了,这时候输入一个对应的值x,直接输出a[x]即为问题的解,时间复杂度为O(n);
接下来自然而然的就会想,函数递归调用结合数组也具有相同的能力储结果

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace  std;
int a[55];
int func(int x)
{
    if(a[x])//如果a[x]不为0,说明a[x]被计算过了,或是已经有了初始值
    return a[x];
    //如果a[x]没有被计算过,说明需要递归;
    a[x]=func(x-1)+func(x-2);
    return a[x];
}
int main()
{
    memset(a,0,sizeof(a));//其实不需要
    a[0]=a[1]=1;
    func(55);//这是说,从高向低开始递归
    int no;
    scanf("%d",&no);
    printf("%d",a[no]);
    return 0;
}

但是,在实际过程中又出现了一个不大不小的问题:数据溢出了!也就是说,32位的数字已经无法储存结果了。因此我们需要64位的整型参与运算
针对不同的编译器,有了两种解决对策:
VC++:64位整型的数类型为_int64,那么输入输出的时候就要写成printf(“%I(大写的i)64d”,a[50]);这种数据类型不支持输入输出流的>>和<<操作
GC++:64位整型的数据类型位long long (int),输入输出的时候写成printf(“%lld”,a[50]);longlong类型同时支持输入输出流的>>和<<;
也就是说,一类题让我知道了两种解题方法,两个避开小陷阱的方法。
开心o( ̄▽ ̄)ブ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值