【递推】菲波那契数列(c++)

【递推】菲波那契数列

题目部分

描述

阅读部分

递推算法使用“步步为营”的方法,不断利用已有的信息推导出新的东西。简单的说就是从已知结果推导出拟求解的问题。

递推算法是一种很高效的算法,如果你能推导出递推式的话。递推难就难在如果推导出递推式。

顺推法:是指从已知条件出发,逐步推算出要解决问题的方法。例如:斐波拉契数列就可以通过顺推法不断递推算出新的数据。

逆推法:是从已知的结果出发,用迭代表达式逐步推算出问题开始的条件,即顺推法的逆过程。

递推的精髓在于f(n)f(n)的结果一般由f(n-1),f(n-2) \dots f(n-k)f(n−1),f(n−2)…f(n−k)的前kk次结果推导出来。我们在解决这类递推问题时,难点就是如何从简单而特殊的案例,找到问题的一般规律,写出f(n)f(n)与f(n-1),f(n-2) \dots f(n-k)f(n−1),f(n−2)…f(n−k)之间的关系表达式,从而得出求解的结果。在历年noip的复赛当中,参赛选手对于这类题目都有这样的感受,往往花费了大量的时间来分析题目的一般规律,写出f(n)f(n)的一般表达式,而编程实现可能只需要几分钟的时间。所以我们在平时训练的时候,对于这样的递推题目,就必须掌握如何分析问题,从特殊推导出一般的规律,写出想要的关系表达式,问题就迎刃而解了。比如NOIP2017day1 题1

递推的题目要特别注意边界情况

参考资料(也可自行百度)

题目部分

菲波那契数列是指这样的数列: 数列的第一个和第二个数都为1,接下来每个数都等于前面2个数之和。

给出一个正整数kk,要求菲波那契数列中第kk个数是多少。

输入

输入一行,包含一个正整数k。(1≤k≤46)

输出

输出一行,包含一个正整数,表示菲波那契数列中第kk个数的大小

输入样例 1 

19

输出样例 1

4181

提示

---------------------------------------------------------------------------------------------------------------------------------

思路

这是一道非常经典的递推题,我们很容易就能知道递推式 f [ i ]= f [ i-1 ]+ f [ i-2 ]

我们也很容易就能知道递推边界:计算到1或者2时,直接返回1

也就是说,我们代码这么写就好了:

int f(long long a){
    if(a==1||a==2)return 1;
    else return f(a-1)+f(a-2);
}

可是事情真的这么简单吗?

我们知道,这道题的数据范围是k小于等于46,这个范围看起来很小,但足以让你超时:

 看见了吗?整整用了两秒钟!

可是,这个代码看起来没有什么问题,那是什么原因导致的?

这是计算斐波那契数列第五项的过程,我们需要算出f(4)和f(3),f(4)又要算出f(3)和f(2)……

发现了吗?在计算的过程中,有很多的数字进行了重复的计算,比如f(3)就计算了两次,如果数据再大一点,那就直接超时了

那有什么解决方案吗?

当然有了!我们可以定义一个大小为46的数组a,用来存储斐波那契数列的每一项,比如a[5]就代表斐波那契数列的第五项,我们只要计算到第五项,我们就把第五项的结果存储起来,下次我们需要第五项的时候,我们直接把我们存好的第五项拿起来用就好了

---------------------------------------------------------------------------------------------------------------------------------

代码:

#include<bits/stdc++.h>
using namespace std;
long long a[50];//用数组a来存储,定义在这里数组a的每一项都是0 
int f(int n){
	if(a[n]>0){//如果a[n]>0,说明第n项已经计算过了 
		return a[n];//直接把结果返回 
	}else if(a[n]==0){//如果是0,说明还没计算过 
		a[n]=f(n-1)+f(n-2);//计算出来存到a数组里 
		return a[n];//返回结果 
	}
}
int main(){
	long long n;
	cin>>n;
	a[1]=1;a[2]=1;//前两项为1 
	cout<<f(n);//输出答案 
	return 0;
}

你听懂了吗?

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值