http://projecteuler.net/index.php?section=problems&id=84
基本的にProblem 280と同じだが、圧倒的に複雑。遷移確率を求めて、100回目の分布を計算する。しかし、どこかが間違っているらしい。結果的には正しい答えが出てくるが。
以前はどうやったのかコードを見てみたら、100万回シミュレートしていた。
import qualified Data.Map as M import Data.List nface = 4 const_p = 1 / 16 collect a = M.toList (f a M.empty) where f [] m = m f ((n,p):xs) m = f xs (M.insert n q m) where q = if M.member n m then (m M.! n) + p else p dices m n k | m == n && k == 3 = [(-1, const_p)] | m == n = [ (if l > 0 then n + n + l else -1, p * const_p) | i <- [1..nface], j <- [1..nface], (l, p) <- dices i j (k+1) ] | otherwise = [(m + n, const_p)] dice = collect (concat [ dices m n 1 | m <- [1..nface], n <- [1..nface] ]) next :: Int -> [(Int, Double)] next n = collect (concat [ g n e | e <- dice ]) where g n (-1,p) = [ (10, p) ] g n ( m,p) = [ (l, p * q) | (l, q) <- f (mod (n + m) 40) ] f n = if n == 30 then [(10, 1.0)] else if n == 2 || n == 17 || n == 33 then [(0, 1 / 16),(10, 1 / 16),(n, 14 / 16)] else if n == 7 || n == 22 || n == 36 then [(0, 1 / 16),(10, 1 / 16),(11, 1 / 16),(24, 1 / 16), (39, 1 / 16),(5, 1 / 16),(n, 6 / 16), (nextr n, 2 / 16),(nextu n, 1 / 16)] ++ (back3 n) else [(n, 1.0)] nextr n = mod ((div (n + 5) 10) * 10 + 5) 40 nextu n = if 12 <= n && 28 < n then 28 else 12 back3 n = [ (m, p / 16) | (m, p) <- f (n - 3) ] step ps = collect [ (m, p * q) | (n, p) <- ps, (m, q) <- next n ] a = [(0, 1.0)]:[ step e | e <- a ] b = sortBy (\x y -> compare (snd y) (snd x)) (a!!100) main = print (take 3 (map fst b))