Problem 232

232 The Race
Problem 232 - Project Euler
コインゲームの勝率を求める問題.
こういうゲームは選択肢が多いほうが有利に決まっている.
典型的なDPだと思う.
現在の得点を状態として,DPを組んだ.
確率の計算に手間取ったのは秘密だ.

import Data.Array (Array, (!), listArray, range, bounds)

prob :: Array (Int, Int) Double -> (Int, Int) -> Double
prob ps (p1, p2) | p2 >= u  = 1
                 | p1 >= u  = 0
                 | otherwise = ps ! (p1, p2)
    where ( (0,0), (u,_) ) = bounds ps

bestProb :: Int -> ( (Int, Int) -> Double) -> (Int, Int) -> Double
bestProb u pr (p1, p2) =
    maximum [
 ( pr (p1 + 1, p2 + q) + pr (p1, p2 + q) + pr (p1 + 1, p2) * ( d - 1 ) ) / ( d + 1 )
     | t <- [1..1+u_t] , let q = 2 ^ (t - 1), let d = 2 ** fromIntegral t]
    where u_t = ceiling.logBase 2.fromIntegral $ u - p2

p232 :: Int -> Double
p232 u = 0.5 * ps ! (0, 0) + 0.5 * ps ! (1, 0)
    where ps = listArray ( (0,0), (u,u) ).map (bestProb u (prob ps)).range $ ( (0,0), (u,u) )

main :: IO ()
main = print $ p232 100

はじめ,Arrayではなく,UArrayをつかっていて,遅延評価が効かず,途方に暮れていた.
まったく,阿呆ですね.