fibonacci数列和跳台阶问题

首先百度之后知道,fibonacci数列其实在科学中有着广泛的应用,下面一句话引子百度百科:在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用。
了解fibonacci数列的人都知道它的推到公式:
   0                       n=0
f(n)=1                       n=1
         f(n-1)+f(n-2)   n>=2
有时候遇到的问题是如何求解fibonacci数列的各项的值,我记得有两种方法,就是递归方法和应用循环的方法。下面给出两种程序的代码:

#include<stdio.h>
int fibonacci_recursion(int n)
{//递归算法
	int result[2]={0,1};
	if(n<2)
		return result[n];
	else
		return fibonacci_recursion(n-1)+fibonacci_recursion(n-2);
}
int fibonacci_non_recursion(int n)
{//非递归算法
	int result[2]={0,1};
	if(n<2)
		return result[n];
	int i;
	int fa=0,fb=1,fc;
	for(i=1;i<n;i++)
	{
		fc=fa+fb;
		fa=fb;
		fb=fc;
	}
	return fc;
}
void main()
{
	int n;
	printf("input n value:");
	scanf("%d",&n);
	printf("%d\n",fibonacci_recursion(n));
	printf("%d\n",fibonacci_non_recursion(n));
}

上面的两个方法都是在O(N)的时间内得到解,但是在csdn的论坛上看到有人说,可以再O(logn)时间内求得fibonacci数列的第n项值,于是google了一下,找到了一篇博文,的确可以在O(logn)内求解。
有一个数学公式: {f(n), f(n-1), f(n-1), f(n-2)} ={1, 1, 1,0} n-1

(注:{f(n+1), f(n), f(n), f(n-1)}表示一个矩阵。在矩阵中第一行第一列是f(n+1),第一行第二列是f(n),第二行第一列是f(n),第二行第二列是f(n-1))

下面就来证明一下这个公式的正确性:fibonacci的第0项为0,第一项和第二项分别是1,所以有公式{1,1,1,0},然后第三项为2,那么有公式{2,1,1,1},此时k=3,则计算第一个公式的平方结果是{2,1,1,1},结果正对,假设k=n-1时,公式成立,就有{f(n-1), f(n-2), f(n-2), f(n-3)} ={1, 1, 1,0}n-2

由fibonacci数列的递推式可以得到{f(n),f(n-1),f(n-1),f(n-2)}={f(n-1)+f(n-2),f(n-1),f(n-2)+f(n-3),f(n-2)},因为计算的原因,公式中第二项和第四项不用代换,可以看出,这个结果就是{f(n-1), f(n-2), f(n-2), f(n-3)}与{1,1,1,0}相乘的结果。故原式得证。

如果简单第从0开始循环,n次方将需要n次运算,并不比前面的方法要快。但我们可以考虑乘方的如下性质:

        /  an/2*an/2                      n为偶数时
an=
        \  a(n-1)/2*a(n-1)/2            n为奇数时

要求得n次方,我们先求得n/2次方,再把n/2的结果平方一下。如果把求n次方的问题看成一个大问题,把求n/2看成一个较小的问题。这种把大问题分解成一个或多个小问题的思路我们称之为分治法。这样求n次方就只需要logn次运算了。

实现这种方式时,首先需要定义一个2×2的矩阵,并且定义好矩阵的乘法以及乘方运算。当这些运算定义好了之后,剩下的事情就变得非常简单。完整的实现代码如下所示。

#include<stdio.h>
#include<assert.h>
struct Matrix2By2
{
	int m_00;
	int m_01;
	int m_10;
	int m_11;
	Matrix2By2(int m00=0,int m01=0,int m10=0,int m11=0):m_00(m00),m_01(m01),m_10(m10),m_11(m11)
	{
	}
};
Matrix2By2 MatrixMultiply(const Matrix2By2& matrix1,const Matrix2By2& matrix2)
{
	return Matrix2By2(
            matrix1.m_00 * matrix2.m_00 + matrix1.m_01 * matrix2.m_10,
            matrix1.m_00 * matrix2.m_01 + matrix1.m_01 * matrix2.m_11,
            matrix1.m_10 * matrix2.m_00 + matrix1.m_11 * matrix2.m_10,
            matrix1.m_10 * matrix2.m_01 + matrix1.m_11 * matrix2.m_11);
}
Matrix2By2 MatrixPower(unsigned int n)
{
	assert(n>0);
    Matrix2By2 matrix;
	if(n==1)
		matrix=Matrix2By2(1,1,1,0);
	else if(n%2==0)
	{
		matrix=MatrixPower(n/2);
		matrix=MatrixMultiply(matrix,matrix);
	}
	else if(n%2==1)
	{
		matrix = MatrixPower((n - 1) / 2);
        matrix = MatrixMultiply(matrix, matrix);
        matrix = MatrixMultiply(matrix, Matrix2By2(1, 1, 1, 0));
	}
	return matrix;
}
int fibonacci_solution(unsigned int n)
{
      int result[2] = {0, 1};
      if(n < 2)
            return result[n];

      Matrix2By2 PowerNMinus2 = MatrixPower(n - 1);
      return PowerNMinus2.m_00;
}
void main()
{
	unsigned int n;
	printf("input n value:");
	scanf("%d",&n);
	printf("%d\n",fibonacci_solution(n));
}
运行,能得到正确的结果。就像题目所说,给我fibonacci在我们计算机中的一个应用吧,就是跳台阶的问题。给定n个台阶,有两种选择,就是一次可以跳一个台阶,还有是一次可以跳两个台阶。求总共有多少总跳法,并分析算法的时间复杂度。 把n级台阶时的跳法看成是n的函数,记为f(n)。当n>2时,第一次跳的时候就有两种不同的选择:一是第一次只跳1级,此时跳法数目等于后面剩下的n-1级台阶的跳法数目,即为f(n-1);另外一种选择是第一次跳2级,此时跳法数目等于后面剩下的n-2级台阶的跳法数目,即为f(n-2)。因此n级台阶时的不同跳法的总数f(n)=f(n-1)+(f-2)。

    我们把上面的分析用一个公式总结如下:
        /  1                             n=1
f(n)=      2                          n=2
        \  f(n-1)+(f-2)            n>2

如果有三种选择就是一次可以分别跳1,2,3,次的话,这个递推式就可以写成:f(n)=f(n-1)+f(n-2)+f(n-3).


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值