diff options
| -rw-r--r-- | 5-2.hs | 93 | 
1 files changed, 93 insertions, 0 deletions
| @@ -0,0 +1,93 @@ +data Graph a = Graph { vertices :: [(Int,a)], edges :: [(Int,Int)] } + +indices :: Graph a -> [Int] +indices (Graph vs _) = map fst vs + +nextIdx :: Graph a -> Int +nextIdx (Graph [] _) = 0 +nextIdx g = succ . maximum . indices $ g + +getIdx :: Eq a => a -> Graph a -> Int +getIdx x = fst . head . filter ((== x) . snd) . vertices + +addVertex :: Eq a => a -> Graph a -> (Int,Graph a) +addVertex x g = (idx,g') +  where +    isElem = x `elem` map snd (vertices g) +    idx = if isElem then getIdx x g else nextIdx g +    g'  = if isElem then g else g { vertices = (idx,x) : vertices g } + +addEdge :: Eq a => Graph a -> a -> a -> Graph a +addEdge g p q = g' { edges = (p',q') : edges g } +  where +    (p',g'') = addVertex p g +    (q',g')  = addVertex q g'' + +fromEdges :: [(Int,Int)] -> Graph Int +fromEdges = fr (Graph [] []) +  where +    fr :: Graph Int -> [(Int,Int)] -> Graph Int +    fr g [] = g +    fr g ((p,q):pqs) = fr (addEdge g p q) pqs + +roots :: Graph a -> [(Int,a)] +roots (Graph vs es) = filter f vs +  where +    f (x,_) = notElem x . map snd $ es + +removeIdx :: Int -> Graph a -> Graph a +removeIdx n (Graph vs es) = let vs' = filter ((/= n) . fst) vs +                                es' = filter f es +                                f (p,q) = p /= n && q /= n +                            in Graph vs' es' + +removeIdxs :: Graph a -> [Int] -> Graph a +removeIdxs = foldr removeIdx + +removeRoots :: Graph a -> Graph a +removeRoots g = removeIdxs g . map fst . roots $ g + +toList :: Graph a -> [a] +toList = tl [] +  where +    tl :: [a] -> Graph a -> [a] +    tl xs (Graph [] _)  = xs +    tl xs g = tl (map snd (roots g) ++ xs) (removeRoots g) + +pairs' :: [a] -> [(a,a)] -> [(a,a)] +pairs' [] ys = ys +pairs' (x:xs) ys = pairs' xs (ys ++ map (x,) xs) + +pairs :: [a] -> [(a,a)] +pairs xs = pairs' xs [] + +filterRules :: Eq a => [a] -> [(a,a)] -> [(a,a)] +filterRules xs = filter (\ (p,q) -> p `elem` xs && q `elem` xs) + +ordered :: Eq a => [(a,a)] -> [a] -> Bool +ordered ps xs = all (`elem` pairs xs) $ filterRules xs ps + +parse :: String -> ([(Int,Int)], [[Int]]) +parse s = (map pair ls, map list ks) +  where +    (ls,_:ks) = span (/= "") (lines s) +    pair r  = let (p,_:q) = span (/= '|') r in (read p, read q) +    list r  = read ("[" ++ r ++ "]") :: [Int] + +incorrects :: String -> [[Int]] +incorrects s = let (ps,xss) = parse s in filter (not . ordered ps) xss + +middle :: [a] -> a +middle xs = xs !! (length xs `div` 2) + +order :: [(Int,Int)] -> [Int] -> [Int] +order rules xs = let rules' = filterRules xs rules +                 in toList . fromEdges $ rules' + +main :: IO () +main = do +  s <- getContents +  let rules = fst (parse s) +  let xs = incorrects s +  let result = sum . map (middle . order rules) $ xs +  print result |