Problem 15

Starting in the top left corner of a $2\times2$ grid, there are 6 routes (without backtracking) to the bottom right corner.

(figure is omitted)

How many routes are there through a $20\times20$ grid?

$2\times2$の格子の左上隅からスタートして,右下隅に,逆戻りしないで到着するには6通りの経路がある

(図は省略)

では,$20\times20$ の格子では何通りの経路があるか.

Haskell

これは受験問題でよくあるもので,単に二項係数${}_{40}\mathrm{C}_{20}$を計算すれば,それが答えです.ただし,再帰的に計算しないと値が爆発しますし,再帰的に計算したらそれはそれで再帰回数が爆発するので,キャッシュする必要があります.ということで,Stateモナドの出番です.枠組みそのものはフィボナッチ数列と全く同じです.

{-
Project Euler Problem 15 e15.hs
-}

import Control.Monad.State

type Cache = [((Integer,Integer),Integer)] -- キャッシュ

ccomb:: (Integer,Integer) -> State Cache Integer
ccomb (n,r)
    | n <  0 = return 0 -- パスカルの
    | r <  0 = return 0 -- 三角形の外の値のために
    | r >  n = return 0 -- (正しい引数だけがくるなら不要)
    | n == 0 = return 1
    | r == n = return 1
    | r == 0 = return 1
    | otherwise
          = do cache <- get
               case (lookup (n,r) cache) of
                   Just k  ->  return k
                   Nothing ->  do num <- liftM2 (+) (ccomb (n-1, r)) (ccomb (n-1, r-1))
                                  cache <- get
                                  put (cache++[((n,r),num)])
                                  return num

comb :: (Integer,Integer) -> Integer
comb = flip evalState [] . ccomb

ghciでの処理の結果

*Main> comb (40,20)
137846528820
(0.03 secs, 5674944 bytes)

となりました.キャッシュなしだと悲惨なくらいの時間がかかります.