回 帖 发 新 帖 刷新版面

主题:快速fibonacci变换

如何快速得到fibonnacci数列的某一项? 该帖改编自HAKMEM:
http://www.inwap.com/pdp10/hbaker/hakmem/recurrence.html#item12

定义一个二元数数乘法:
(A,B) (C,D) = (A C + A D + B C, A C + B D).
我们注意到 (A,B) (1,0) = (A + B, A), 这就是fibonacci的迭代公式.因此有 (1,0)^N = (FIB(N), FIB(N-1)). 这预示我们可以在logN的时间内得到数列的第N项.

例如:FIB(1) => (1,0)^1=(1,0);
FIB(2) => (1,0)^2=(1,1); 
FIB(4) => (1,0)^4=(3,2);
FIB(5) => (1,0)^1 * (1,0)^4=(1,0)*(3,2)=(5,3);
...

下面是实现代码:
#include <iostream>
#include <cstdlib>

using namespace std;

struct Pair {
    int a;
    int b;
};

Pair transform (const Pair &A, const Pair &B)
{
    if (A.a == 0)
        return B;
    Pair tmp;
    tmp.a = A.a*B.a + A.a*B.b + A.b*B.a;
    tmp.b = A.a*B.a + A.b*B.b;

    return tmp;
}

int fast_fibonacci_transform (int n)
{
    assert (n > 0);
    Pair now = {1, 0}, sum = {0, 0};

    if (n & 1) sum = now;
    n >>= 1;
    while (n) {
        now = transform (now, now);
        if (n & 1)
            sum = transform (sum, now);
        n >>= 1;
    }

    return sum.a;
}

int main ()
{
    int n = 47;
    for (int i = 1; i <= n; ++i)
        cout << fast_fibonacci_transform (i) << ' ';
    cout << endl;
    system ("pause");
    return 0;
}

输出:
1 1 2 3 5 8 13...

回复列表 (共17个回复)

沙发

这个其实是距阵的一个利用

板凳

能讲一下吗?这跟矩阵有什么关系?矩阵乘法不满足交换率,可这个满足.

3 楼

有结合律就行了

O(logn)要求取模的,原来做OJ的时候看到过资料。

fibonacci有通项公式,我一本书上有推导

4 楼

fibonacci我有个高中同学把通项愣算了一下午算出来了
一堆aqrt(5)阿……

5 楼

神奇的矩阵! rick把那个oj资料找一找啊...

6 楼

[quote]fibonacci我有个高中同学把通项愣算了一下午算出来了
一堆aqrt(5)阿……[/quote]

呵呵 菲数列就是比较有趣 所有项都是有理数 而通项需要用无理数来表示

7 楼

2euc:我BLOG里有

我现在会推了,用母函数,最简单的一种了,叫线性递推公式

8 楼

太汗了,母函数我每次都看不懂

9 楼

通项公式(偶刚刚推的,应该对的吧):
(pow( (1+sqrt(5)) , n ) - pow( (1-sqrt(5)) , n )) / (pow(2,n) * sqrt(5))

10 楼

直接用通项应该最快了
嘿嘿

我来回复

您尚未登录,请登录后再回复。点此登录或注册