Project Euler Problem 14(その4)
コラッツ問題でなんとか答えはでていますが,せっかくStateモナドを頑張ったので,それで書いてみます.
StateモナドがMonadFixのインスタンスだとかは・・・スルーします.
import Control.Monad.State import Data.List {- Project Euler Problem 14 e14-8.hs -} type Cache = [(Integer, Integer)] -- 整数とそれに対するコラッツ列の長さ -- コラッツ列を求める collatz::Integer -> State Cache Integer collatz 1 = return 1 collatz n = do cache <- get case (lookup n cache) of Just k -> return k Nothing -> do num <-if n `mod` 2 ==0 then collatz (n `div` 2) else collatz (3*n+1) cache <- get put ((n,num+1):cache) return (num+1) f xs n= execState (collatz n) xs g n = foldl f [] [1..n]
g 10などとすると,1から10までに対する「コラッツの列」の長さと,その途中計算で出てくる数とそのコラッツの列の長さがタプルででてきます.例えば
g 10 [(9,20),(28,19),(14,18),(7,17),(22,16),(11,15),(34,14),(17,13),(52,12),(26,11),(13,10),(40,9),(20,8),(6,9),(3,8),(10,7),(5,6),(16,5),(8,4),(4,3),(2,2)]
となります.途中経過も含めてひたすら溜め込みますので,その点では非効率ですが,それなりに動きます.この結果を加工すれば,「長さ最大のコラッツ列」を求めることは容易でしょう.
残念ながら,この溜め込み方だとstack over flowがでてきて1,000,000は計算できません.溜め込むものを適宜カットする必要があります.