菲波那契数列的快速幂矩阵求法

时间;2014.05.15

地点:基地二楼

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

一、背景

著名的斐波那契数列为一个这样的序列:0 1 1 2 3 5 8 13 21 34......简单的递推公式如下:

F(0)=0,F(1)=1,当n>=1时,F(n)=F(n-1)+F(n-2)

显然,我们用直接的按公式递归的算法去计算该数列的第n项效率并不高,因为这样每次递归调用我们只是将规规模缩小了一点点,我们常用的递归都是将规模减半吧~,所以在这里这么用递归并不高效,我是终于又看到一个O(log)的算法了,还一个是二分查找,时间复杂度为O(logn)的算法并不多见,通过合理的算法设计,能将一个复杂的算法降到对数时间,真是神奇。在这里我将用到的是快速幂的思想。

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

二、快速幂算法

前面有文章已经介绍过快速幂,通过求数幂来说明,比如求数7的5次方,我们知道5用二进制表示为101,于是我们按101这个序列从右至左,每次用7去乘当前7的幂,若是碰到1,还将当前得到的值与当前7的幂相乘。比如在这里7的5次方7(5)=7(1)*7(4)。计算过程为这样,从最右边开始,我们首先碰到1,于是将当前目标值为7(1),当前幂值平方为7(2),接下来碰到一个0,于是当前目标值不变,幂值 平方得7(4),再接下来碰到1,于是将当前目标值7(1)与当前幂值7(4)相乘,得新的目标值7(5),当前幂平方得7(8)。再接下来都是0了,就无需继续了,这可以通过将幂5的二进制形式不断右移实现。比如在这里,我们的斐波那契矩阵求法是基于等式:

|    F(n-1)     F(n)         |                           |           0       1              |  (n)

|                                  |          =               |                                    |                =B^n

|    F(n)        F(N+1)    |                           |            1       1             |

那么我们这里即就是计算矩阵B的n次方而已,这个算法的伪代码如下:

long long CaculateFibonacci(size_t n)
{
  初始化目标矩阵为单位矩阵A,这里恰好对应F(0)=0
  初始化基矩阵为B的形式
  为了在计算矩阵乘法过程中保持原矩阵我们还需设定4个临时变量
  while(只要当前n非0)
  {
      if(当前n的最低位为1)
      {
        将目标矩阵A与当前基矩阵相乘
      }
      在每次循环中均将当前基矩阵平方处理,于是可得到A^2 A^4 A^8 A^16等
      将n右移一位
   }
}
      

三、代码实现如下:

#include<iostream>
#include<cassert>
using namespace std;
long long CaculateFibonacci(size_t n)
{
	//Precondition:
	//Postcondition:
	assert(n >= 0);
	long long ans_arr[2][2] = { 1, 0, 0, 1 };
	long long base_arr[2][2] = { 0, 1, 1, 1 };
	long long temp00 = 0, temp01 = 0, temp10 = 0,temp11 = 0;
	while (n)
	{
		if (n & 1)  //当前最低位为1,将目标矩阵与当前基矩阵对应的幂阵相乘
		{
			temp00 = ans_arr[0][0], temp01 = ans_arr[0][1], temp10 = ans_arr[1][0], temp11 = ans_arr[1][1];
			ans_arr[0][0] = temp00 * base_arr[0][0] + temp01 * base_arr[1][0];
			ans_arr[0][1] = temp00 * base_arr[0][1] + temp01 * base_arr[1][1];
			ans_arr[1][0] = temp10 * base_arr[0][0] + temp11 * base_arr[1][0];
			ans_arr[1][1] = temp10 * base_arr[0][1] + temp11 * base_arr[1][1];
		}
	    //从基矩阵计算当前相应的幂阵
		temp00 = base_arr[0][0], temp01 = base_arr[0][1], temp10 = base_arr[1][0], temp11 = base_arr[1][1];
		base_arr[0][0] = temp00 * temp00 + temp01 * temp10;
		base_arr[0][1] = temp00 * temp01 + temp01 * temp11;
		base_arr[1][0] = temp10 * temp00 + temp11 * temp10;
		base_arr[1][1] = temp10 * temp01 + temp11 * temp11;
		n >>= 1;
	}
	return ans_arr[0][1];
}
int main()
{
	cout << "Input n: " << endl;
	int n = 0;
	cin >> n;
	long long a = CaculateFibonacci(n);
	cout <<"The result is: "<< a << endl;
}

菲波那契数列的快速幂矩阵求法,布布扣,bubuko.com

时间: 2024-09-29 17:19:35

菲波那契数列的快速幂矩阵求法的相关文章

递推-练习1--noi1760 菲波那契数列(2)

递推-练习1--noi1760 菲波那契数列(2) 一.心得 二.题目 1760:菲波那契数列(2) 总时间限制:  1000ms 内存限制:  65536kB 描述 菲波那契数列是指这样的数列: 数列的第一个和第二个数都为1,接下来每个数都等于前面2个数之和.给出一个正整数a,要求菲波那契数列中第a个数对1000取模的结果是多少. 输入 第1行是测试数据的组数n,后面跟着n行输入.每组测试数据占1行,包括一个正整数a(1 <= a <= 1000000). 输出 n行,每行输出对应一个输入.

菲波那契数列编程实现

http://blog.csdn.net/pipisorry/article/details/37660419 斐波那契数列又因数学家列昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为"兔子数列". fibonacci 数列定义: n = 1,2 时,fib(n) = 1 n > 2 时,fib(n) = fib(n-2) + fib(n-1) 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597,

递归--练习6--noi1755菲波那契数列

递归--练习6--noi1755菲波那契数列 一.心得 二.题目 1755:菲波那契数列 总时间限制:  1000ms 内存限制:  65536kB 描述 菲波那契数列是指这样的数列: 数列的第一个和第二个数都为1,接下来每个数都等于前面2个数之和.给出一个正整数a,要求菲波那契数列中第a个数是多少. 输入 第1行是测试数据的组数n,后面跟着n行输入.每组测试数据占1行,包括一个正整数a(1 <= a <= 20) 输出 输出有n行,每行输出对应一个输入.输出应是一个正整数,为菲波那契数列中第

2017-3-5 函数 函数返回多个值 递归和菲波那契数列练习

(一)函数的定义:非常抽象,独立完成某项功能的独立个体. 作用:1提高代码的重用性 2提高功能开发的效率性 3提高程序代码的可维护性 函数分为   固定功能函数  高度抽象函数 函数的4要素:输入  输出  函数名  函数体 函数的多种形态: 1.   4要素齐全的 public static 返回值类型 函数名(需要的参数,可以多个,多种数据类型) { 函数体 return 返回返回值类型的数据 } 2.  有参数无返回值的 public ststic void 函数名(参数) { 函数体 }

js获取菲波那契数列的第N个元素

菲波那契数列,大致可以描叙为a(n) = a(n-1) + a(n-2) (a >=2).类似于这样[1, 1, 2, 3, 5, 8, 13 ...]. 具体大家可以百度一下.下面我们来用js获取菲波那契数列的第N个数为多少: 1.递归 var a = function(n) { if (n === 1 || n === 2) { return 1 } else { return a(n - 1) + a(n - 2) } } console.time('a(44)') console.log

1-5-13:菲波那契数列

描述 菲波那契数列是指这样的数列: 数列的第一个和第二个数都为1,接下来每个数都等于前面2个数之和.给出一个正整数k,要求菲波那契数列中第k个数是多少. 输入输入一行,包含一个正整数k.(1 <= k <= 46)输出输出一行,包含一个正整数,表示菲波那契数列中第k个数的大小 样例输入 19 样例输出 4181 来源1755 #include<stdio.h> int main() { int k,i,a1=1,a2=1,a=1; scanf("%d",&

菲波拉契数列(传统兔子问题)

题目: 古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 斐波那契数: 亦称之为斐波那契数列(意大利语: Successione di Fibonacci),又称黄金分割数列.费波那西数列.费波拿契数.费氏数列,指的是这样一个数列:0.1.1.2.3.5.8.13.21.……在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=Fn-1+Fn-2(n>=2,n∈N*),用文字来说,就

2753:菲波那契数列

2753:菲波那契数列 查看 提交 统计 提示 提问 总时间限制:  1000ms 内存限制:  65536kB 描述 菲波那契数列是指这样的数列: 数列的第一个和第二个数都为1,接下来每个数都等于前面2个数之和.给出一个正整数a,要求菲波那契数列中第a个数是多少. 输入 第1行是测试数据的组数n,后面跟着n行输入.每组测试数据占1行,包括一个正整数a(1 <= a <= 20) 输出 输出有n行,每行输出对应一个输入.输出应是一个正整数,为菲波那契数列中第a个数的大小 样例输入 4 5 2

POJ 2753:菲波那契数列

AC代码: import java.util.Scanner; public class Main { /** * 利用递推得到第n个斐波拉契数 * @param n * @return */ private static int getFibonacciN(int n) { if (n > 2) { return (getFibonacciN(n - 1) + getFibonacciN(n - 2)); }else { return 1; } } public static void mai