カタラン数を計算してみる、その2

前回はfactorialとcombinationでカタラン数を導出しようと、fact 20くらいであっけなくオーバーフローしたけど、チーター本のP.216ではカタラン数をDPで計算してる。けど、問題の解説見てて{C_0=1}があったほうが分かり易いなと何となく思った*1


{C_0=1}を定義した場合



{C_0 = 1}
{C_1= C_0*C_0 =1}
{C_2= C_1*C_0+C_0*C_1 =2}
{C_3= C_2*C_0+C_1*C_1+C_0*C_2 =5}
{C_4= C_3*C_0+C_2*C_1 + C_1*C_2+C_0*C_3 = 14}
{C_5 = ...  = 42}
{C_n = C_{n-1}*C_0 + C_{n-2}*C_1 + ... + C_1*C_{n-2} + C_0*C_{n-1} }

しなかった場合(書籍の解説より引用)



C0=1
{C_1=1}
{C_2= C_1+C_1 =2}
{C_3= C_2+C_1*C_1+C_2 =5}
{C_4= C_3+C_2*C_1 + C_1*C_2+C_3 = 14}
{C_5 = ...  = 42}
{C_n = C_{n-1} + C_{n-2}*C_1 + ... + C_1*C_{n-2} + C_{n-1} }

で、{C_n}の一般項は、本の通りになると腑に落ちた。それだけ*2w−



ってわけのいかないので、それでコード書いてみた。けど、本のサンプルのDPは*3よく分からないので
Ruby*4再帰で書き下すw−。

$memo = Array.new(10, 0)
$memo[0] = 1

def catalan n
  return $memo[n] unless $memo[n].zero?

  $memo[n] = (1..n).to_a.reduce(0){|s,i|
    #p [s,i]
    p [$memo]

    s + catalan(n-i) * catalan(i-1)
  }
  $memo[n]
end

それっぽい答え出てるけど、早いのかどうかわからないw−

P.S.
前回のfactorial使ったのと、今回のrubyコードの時間計測しても大して変わらないな

$ time ruby catalan.rb
[1, 1]
[2, 2]
[3, 5]
[4, 14]
[5, 42]
[6, 132]
[7, 429]
[8, 1430]
[9, 4862]
[10, 16796]
[11, 58786]
[12, 208012]
[13, 742900]
[14, 2674440]
[15, 9694845]

real    0m0.334s
user    0m0.310s
sys     0m0.020s
$ time ruby catalan_memo.rb
[1, 1]
[2, 2]
[3, 5]
[4, 14]
[5, 42]
[6, 132]
[7, 429]
[8, 1430]
[9, 4862]
[10, 16796]
[11, 58786]
[12, 208012]
[13, 742900]
[14, 2674440]
[15, 9694845]

real    0m0.321s
user    0m0.300s
sys     0m0.010s

*1:って思ったけど、wikipediaがそのような導出なのでそれ見ただけかもw−

*2:全部書くの面倒くさいので、詳細は本を参照してください^^

*3:ってよりループにかな。本質的に再帰と等価だからforで記述できそうなのは分かるけどw−

*4:慣れているのでwww