Project Euler 79

http://projecteuler.net/index.php?section=problems&id=79


ものすごくいい加減な解法。数字が右にあるか左にあるか、各ペアで調べる。50個のリストでそれがすべて分かるので、順番が付けられる。

import Data.List

import qualified Data.Map as M
import qualified Data.Set as S

digits :: Int -> [Int]
digits 0 = []
digits n = (digits (div n 10)) ++ [mod n 10]
to_number a = foldl1 (\x y -> x * 10 + y) a

used_digits a = S.toList (f S.empty a) where
        f s [] = s
        f s (d:ds) = f (S.insert d s) ds

solve a = to_number (sortBy cmp ds) where
        ds = used_digits (concat a)
        ds2 = [ (x, y) | x <- ds, y <- ds, x /= y ]
        m = update a (M.fromList [ (xy, 0) | xy <- ds2 ])
        update [] m = m
        update (dd:a) m = update2 (g dd) (update a m)
        update2 [] m = m
        update2 ((d,mode):dd) m = M.insert d mode (update2 dd m)
        g [d1, d2, d3] = [ ((d1,d2),1),((d1,d3),1),((d2,d3),1),
                           ((d2,d1),2),((d3,d1),2),((d3,d2),1) ]
        f d = sum [ m M.! (d,d1) | d1 <- ds, d1 /= d ]
        cmp d1 d2 = compare (f d1) (f d2)

main = do
    cs <- readFile "keylog.txt"
    print (solve (map (digits . read) (lines cs)))