Pythonで動的計画法を勉強してみた

ナップサック問題を解いていたら、出てきた「動的計画法」
結構複雑なのでまとめてみた。

2420 views

多分、一回書いてみるのが一番早いと思います。

フィボナッチ数列とは

フィボナッチ数列は、「2つ前の項と1つ前の項を足し合わせていくことでできる数列」のことです。数列は「1,1」から始まり、
1, 1, 2, 3, 5, 8, 13, 21…
と続いていきます。

解いてみる

解いてみるにあたり、まず思いつくのは再帰。
ということで、再帰で検索してみた。

再帰

コード

def fib(n):
 if n <= 2:
   return 1
 else:
   return fib(n-2) + fib(n - 1)

### 出力 ![](/media/section/64bcb85a9f9341c1bfc7ab641bb6e02c.png) ![](/media/section/fb18ee8259a2481796c47255aaeaa5e8.png) ### 欠点 このままでよさそうだが、 **遅えぇぇぇ** 40番目や100番目等後ろの値を取得するとき、処理が極端に遅くなる。 ※実際、100番目を取得しようとして全然帰ってこなくて心折れた,,, ここで出てくるのが、「動的計画法」 ## 動的計画法 ### コード
# 最大値
MAX_N = 100
DP = [None] * (MAX_N + 1)  # 計算結果を保存する配列
DP[0] = 0  # 定義より
DP[1] = 1  # 定義より

def fib(n):
    # フィボナッチ数を2からnまで順に求めていく
    for i in range(2, n + 1):
        DP[i] = DP[i-1] + DP[i-2]
        print(i,'=', DP[i])
    return DP[n]

#fib()番目を出力する
print(fib(100))


### 出力 ※100番目の出力でもすごい速い!! ![](/media/section/423a8c37006243a1b05eccaf43c43751.png) # 動的計画法はなぜはやい? 今回に関して言うならば、**余計な計算をしていないから**である。 ## 再帰の場合 ![](/media/section/0147f371949f4ba1951f9d5d55516d10.png) 同じ値を何回も求めている ## 動的計画法の場合 ![](/media/section/f3f3d25fa8c54ad7adb0a04be406efbf.png) 同じ値は一回だけ求めている。 # 2種類の動的計画法 動的計画法は、2種類存在する。 「トップダウン」と「ボトムアップ」である。 * トップダウン:メモ化再帰、メモ化 * ボトムアップ:分割統治法、漸化式ループ ※漸化式がわからない文系の諸君!!僕もです。余裕があれば別紙で解説します。 ※一応画像を載せます(参考:https://juken-mikata.net/how-to/mathematics/recurrence-formula.html) ![](/media/section/f0bcaf650b8e4aa6a6f708546dcae529.png) ここで抑えるべきは、**「前の頁に従う」**って点だと思う。 ## トップダウンについて トップダウンは、計算した結果を記録して、同じ数に関しては1度しか計算しないようにする方法である。 上で紹介したコードが該当する。 下記にも一度載せる。 ### コード
# 最大値
MAX_N = 100
DP = [None] * (MAX_N + 1)  # 計算結果を保存する配列
DP[0] = 0  # 定義より
DP[1] = 1  # 定義より

def fib(n):
    # フィボナッチ数を2からnまで順に求めていく
    for i in range(2, n + 1):
        DP[i] = DP[i-1] + DP[i-2]
        print(i,'=', DP[i])
    return DP[n]

#fib()番目を出力する
print(fib(100))

## ボトムアップ
def fib3(n):
# 0ならば、0を返す
  if n==0:
    return 0
  else:
     #fib1,2,3を定義。それぞれ、1
    fib1 = fib2 = fib3 = 1

    i = 0
    while  i < n-2:
            #それぞれ足していく
        fib3 = fib2 + fib1
        fib1 = fib2
        fib2 =fib3
        i += 1
    print(fib2)
    return fib2

...正直よくわからないなぁ,,, 理屈はわかるけど、だから?ってなりそう。

一回まとめよう

  1. 動的計画法を用いると、計算量を減らせる
  2. 動的計画法には二種類ある。「トップダウン」と「ボトムアップ」である
  3. トップダウンは同じ計算を繰り返さないことを目的としている
  4. ボトムアップは最大の値を決めておいて、実行する。

以上!

Page 3 of 5.

前のページ 次のページ



[添付ファイル]


お問い合わせ

プロフィール

owl

自己紹介

駆け出しエンジニア
だいたいweb系をかじってる
最近ちょとブロックチェーンに興味出てきた

サイト/ブログ

https://github.com/owl0109

ツイッター

@kijiken1