この前のをHaskellで解いてみる。
最近はHaskellerらしからぬことばっかりやっていたので、
久しぶりにHaskellを使うことにした。
ここから、割合簡単なADIをHaskellで実装。
とりあえずリハビリということで。
しかし、副作用がないと良い。見通しが立てやすいね。
A問題
import Data.List import Data.Char import Control.Monad import System.IO data Tree = Leaf | Node [Tree] buildTree s = inner s [] where inner [] (t:_) = t inner ('a':ss) stk = inner ss (Leaf:stk) inner (num:ss) stk = inner ss ((Node (reverse c)):r) where (c,r) = splitAt (ord num - ord '0') stk optimize Leaf = (1,"a") optimize (Node ls) = ret where os = map optimize ls len = length ls cand = [calc $ take len $ drop n os++os | n<-[0..len - 1]] calc ls = (dep,str) where dep = maximum [n+d | (n,(d,_)) <- zip [0..] ls] str = concat (map snd ls) ++ [chr (len + ord '0')] ret = minimumBy (\(a,_) (b,_) -> compare a b) cand main = do h <- openFile "chandelier.in" ReadMode num <- hGetLine h ls <- replicateM (read num) (hGetLine h) let as = map (optimize . buildTree) ls mapM_ (\(n,s) -> print n >> putStrLn s) as
D問題
import Data.FiniteMap main = readFile "game.in" >>= mapM (printAns.solve) . takeWhile (/=[0,0]) . map (map read . words) . lines solve [n,m] = filt (==1) (ops!!m) $ foldl (flip $ filt (/=1)) s $ take m ops where s = [(a,b) | a<-[1..n], b<-[a+1..n]] ops = cycle [(+),( * )] filt cond op ls = concat $ filter (cond.length) $ eltsFM $ addListToFM_C (++) emptyFM [(op a b,[(a,b)])| (a,b) <- ls] printAns ls = do print $ length ls mapM_ (\(a,b) -> putStrLn $ show a ++ " " ++ show b) ls putStrLn ""
I問題
import Data.Char import Control.Monad import System.IO data Tree = Node Char [Tree] instance Show Tree where show (Node c []) = [c] show (Node c ls) = [c] ++ "(" ++ concat (map show ls) ++ ")" main = openFile "org.in" ReadMode >>= inner where inner h = do n <- hGetLine h when (read n /= 0) $ do s <- hGetLine h t <- hGetLine h print $ solve (filter (not.isSpace) s) (filter (not.isSpace) t) inner h solve [a] [b] = Node a [] solve (a:as@(aa:_)) (b:bs) = Node a child where roots = takeWhile (/=aa) bs ++ [aa] ar = reverse $ snd $ foldl slice (as,[]) $ tail (reverse roots) ++ "*" br = [filter (`elem` a) bs | a<-ar] child = reverse $ zipWith solve ar br slice (ss,ret) c = (sr,rr:ret) where (rr,sr) = span (/=c) ss
うーん…どれもHaskellならでは…な技を使えたわけでないなぁ。
いたって普通になってしもた。
コードはC++より抜群に短い。
C++のコードは長いので割愛。
A100行、D70行、I100行ぐらい。