情報科学シケスラ fibonacci

23
Information Science Fibonacci Sequence is Magic My Little 2014/01/28 tozangezan

Upload: tozan-gezan

Post on 28-May-2015

326 views

Category:

Education


3 download

DESCRIPTION

情報科学

TRANSCRIPT

Page 1: 情報科学シケスラ Fibonacci

Information Science

Fibonacci Sequence is Magic

My Little

2014/01/28 tozangezan

Page 2: 情報科学シケスラ Fibonacci

はじめに• シケプリではありません ( 特に「プリ」が

違う )• コラムが延々と続く感じです• Ruby 書きたくないのでまともなソース

コードは載せません• 今回は漸化式で表される数列の計算をし

ます。

Page 3: 情報科学シケスラ Fibonacci

扱う漸化式• 以下の式を扱います

• このうちの k と求める項の番号 n が与えられるので、 an を答える方法を考えます。

• k=2 としたものが Fibonacci 数列です。• やり方はたくさんあります。• ( 以下、漸化式の係数をいじればすこし一般化できます )

Page 4: 情報科学シケスラ Fibonacci

関数の再帰を使うF(n){ if n < K then 1 else F(n-1)+F(n-2)+…+F(n-k)}

( 注 ) どの言語でもないので実行できません

• 再帰関数というのは定義した関数の中に同じ関数を呼び出す機構があるものだと思っておけばよいと思います。

• 漸化式をそのままコードに書いたらこんな感じになります。

Page 5: 情報科学シケスラ Fibonacci

遅い!• よく考えると、さっきのコードは少なくと

も「 1 を返す回数」だけ関数が呼ばれています

• これは答えの数と一致

• 例えば、 50 番目のフィボナッチ数は12586269025 で、このプログラムだと数分はかかりそう

• 計算量はだいたい O(αn) α は何かの定数• (Fibonacci 数列なら黄金数とか )

Page 6: 情報科学シケスラ Fibonacci

計算量:指数関数• 基本的に指数関数はダメです• 参考  http://www.youtube.com/watch?v=

Q4gTV4r0zRs

• 「 F(n) は何度も計算したところで毎回値同じでは…」という発想だけで高速になります。

Page 7: 情報科学シケスラ Fibonacci

関数のメモ化再帰をするF(n){ if “F(n) 計算済み” then “ 計算済みの値” if n < K then 1 else F(n-1)+F(n-2)+…+F(n-k)}

( 注 ) どの言語でもないので実行できません

• さっきのものに 2 行書きたし、無駄に計算しないようにしました。

• かなり速く動くようになります。

• まだ漸化式から想像がつくでしょう。

Page 8: 情報科学シケスラ Fibonacci

メモ化再帰での計算量• 関数は n の値あたり 1 回しか呼び出されな

いとしてよい• ( 正確には何回か呼ばれてるだろうけど最

初の 1 文だけだしどうでもいい )• n の値によって関数は 1 回ずつ呼ばれて計

O(n)• 関数 1 回では K 個の数の和を計算するので

O(k)• これら全部まとめると O(nk)• さっきより格段に速い !!

Page 9: 情報科学シケスラ Fibonacci

動的計画法を使うa[N] # 配列a[1]=a[2]=…=a[k]=1for i in (k+1)..n a[i]=a[i-1]+a[i-2]+…+a[i-k]

• 今度は関数を使わずに、ループをまわすだけでかいてみました。

• 本当は k 個の数の和を求めるのでもループを使うんですがね。

• コードが短め。

Page 10: 情報科学シケスラ Fibonacci

動的計画法での計算量• メモ化再帰と同じ• n 回くらいループをまわしていて、 (O(n))• それぞれでは k 個の数の和を計算 (O(k))

• 全部まとめると O(nk)• やっぱりメモ化再帰と同じ

Page 11: 情報科学シケスラ Fibonacci

問題• 以下の数列を考える

• このうちの k と求める項の番号 n が与えられるので、 an を 109+7 で割ったあまりを答えよ。

• k 100≦• n 100 000≦• 解答例: さっきのメモ化再帰 , 動的計画法

Page 12: 情報科学シケスラ Fibonacci

問題• 以下の数列を考える

• このうちの k と求める項の番号 n が与えられるので、 an を 109+7 で割ったあまりを答えよ。

• k 100≦• n 1 000 000 000 000 000 000≦• 解答例: さっきのメモ化再帰 , 動的計画法• さっきの方法では間に合わない!!

Page 13: 情報科学シケスラ Fibonacci

別世界• ここから先はコード書くの面倒なのでか

きません。• 情報科学の試験レベルなら別にこのくら

いでゴールして良いんじゃないでしょうか。• ここから先は k が大きいのには対処できま

せんが、 n が大きいのに対処できる方法です。

Page 14: 情報科学シケスラ Fibonacci

行列累乗• k=2 のとき、

• k=3 のとき、

• k=4 のとき、

Page 15: 情報科学シケスラ Fibonacci

行列累乗• こういう感じの形になるので、 an を得るた

めには 1 を並べたベクトルに n-k 回さっきのような行列をかければよい。

• 行列のかけ算• A, A2, A4, A8, A16, A32, … は同じものをかける処

理をすると、全部で O(log n) 回で求められる• ほかのものが得たいときは、例えば

A21= A × A4 × A16 などと 2 進数っぽくする。

Page 16: 情報科学シケスラ Fibonacci

行列累乗での計算量• ということは、行列のかけ算は O(log n) 回

行えばよい。• ここで使う行列は k 次正方行列なので 1 回

のかけ算は O(k3) かかる ( 定義に従って素直に計算するしかない )

• ということで全体での計算量は O(k3 log n)

Page 17: 情報科学シケスラ Fibonacci

問題• 以下の数列を考える

• このうちの k と求める項の番号 n が与えられるので、 an を 109+7 で割ったあまりを答えよ。

• k 100≦• n 1 000 000 000 000 000 000≦• 解答例: 行列累乗

Page 18: 情報科学シケスラ Fibonacci

問題• 以下の数列を考える

• このうちの k と求める項の番号 n が与えられるので、 an を 109+7 で割ったあまりを答えよ。

• k 1 000≦• n 1 000 000 000 000 000 000≦• 解答例: 行列累乗• さっきの方法では間に合わない!

Page 19: 情報科学シケスラ Fibonacci

整式の割り算を使う方法• 実は、この問題の第 n 項の値は、

「 xn を xk-xk-1-xk-2-…-1 で割ったあまりの係数の総和」に等しいです。 ( 証明略 )

xn を xk-xk-1-xk-2-…-1 で割ったあまりは、 x[n/2]

を xk-xk-1-xk-2-…-1 で割ったあまりを 2 乗し (nが奇数ならさらに x をかける ) 、その式をxk-xk-1-xk-2-…-1 で割ったあまりを求めればよいです。

Page 20: 情報科学シケスラ Fibonacci

整式の割り算を使う方法• k-1 次の多項式二つの乗算は O(k2) ででき

ます• この多項式の乗算は O(log n) 回呼ばれます

• ということで全体での計算量は O(k2 log n)です。

Page 21: 情報科学シケスラ Fibonacci

参考問題• http://tdpc.contest.atcoder.jp/tasks/

tdpc_fibonacci• けっこう多くの言語で (Ruby でも ) 解くこ

とができるっぽいです。• 解答例http://tdpc.contest.atcoder.jp/submissions/119305  (C++, 48 行 )

Page 22: 情報科学シケスラ Fibonacci

おまけ• 整式のかけ算は畳み込みなので FFT で計算

できて O(k log k) になります。• が、その整式を割ったあまりの計算がど

うやったら O(k2) から落ちるかわかりません。

• 誰か教えてください• あと、今回 109+7 で割ったあまりを求めた

のは答えが大きくなりすぎるからです。

Page 23: 情報科学シケスラ Fibonacci

The End