0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[C++] フィボナッチ数列をメモ化再帰でn=93までを高速で出力する

Last updated at Posted at 2020-03-16

[C++] フィボナッチ数列をメモ化再帰でn=93までを高速で出力する

フィボナッチ数列の出力をメモ化再帰を用いて高速に出力しました。

c++のunsigned long long型を用いて$n=93$までを出力できるようにしました。

$n=94$以降はunsigned long long型の最大値$18446744073709551615$を超えてオーバーフローしてしまいます。

また、フィボナッチ数列とは次の漸化式を満たす正の整数列です。

$n$を正の整数として、

A(0) = 0,\ \ \ A(1) = 1 \\
A(n) = A(n-1) + A(n-2)\ \ \ \ \ \ \ \ \ (n>=2)

つまり、

A = \{ 0,\ 1,\ 1,\ 2,\ 3,\ 5,\ 8,\ 13,\ 21,\ ... \}

となる数列である。

実装 [C++]

再帰のみで実装

単純に実装すると、次のようになります。

# include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;

ull fibonacci(ull a);

int main() {
    ull n;
    cin >> n;

    ull ans = fibonacci(n);

    cout << ans << endl;

    return 0;
}

ull fibonacci(ull a) {
    if (a == 0 || a == 1) {
        return a;
    } else {  
        return fibonacci(a-1) + fibonacci(a-2);
    }
}

C++で実装する際に、いくらC++が高速な言語であっても愚直に再帰で解こうとすると計算複雑性は$O(2^n)$となるので$n=50$程度で計算時間が数秒ではなくなってしまいます。

メモ化再帰を利用する

そこで、すでに計算されたフィボナッチ数を記録しておき、それぞれのフィボナッチ数を求める前にすでに計算されいているか確認するようにしました。

もし、すでに計算されていれば、その値を参照するようにします。

次のようになります。

# include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;

ull fibonacci(ull a);

map<ull, ull> fibomap;

int main() {
    ull n;
    cin >> n;

    fibomap[0] = 0;
    fibomap[1] = 1;

    ull ans = fibonacci(n);

    cout << ans << endl;

    return 0;
}

ull fibonacci(ull a) {
    if (a == 0 || a == 1) {
        return a;
    } else {
        if (fibomap.find(a-1) != fibomap.end()) {
            if (fibomap.find(a-2) != fibomap.end()) {
                return fibomap[a-1] + fibomap[a-2];
            } else {
                fibomap[a-2] = fibonacci(a-2);
                return fibomap[a-1] + fibomap[a-2];
            }
        } else {
            if (fibomap.find(a-2) != fibomap.end()) {
                fibomap[a-1] = fibonacci(a-1);
                return fibomap[a-1] + fibomap[a-2];
            } else {
                fibomap[a-1] = fibonacci(a-1);
                fibomap[a-2] = fibonacci(a-2);
                return fibomap[a-1] + fibomap[a-2];
            }
        }
    }
}

メモ化再帰することで計算複雑性は$O(n)$になり高速で計算できます。

しかし、今回はC++のunsigned long long型を使用しているので$n=94$でオーバーフローしてしまいました。

もし、$n=94$以降も高速で求められる方法がありましたら、ぜひコメントで教えてください。

0
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?