Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Rhyme.hs
- module Main where
- import Data.Char
- import Data.List
- import Data.Array
- import Data.Function
- import Data.List.Split
- import Data.String.Utils
- import System.IO
- import BestMatching
- testInput = "Боже! думает бедняк,\nБедный Ваня еле дышит,\nВесь в поту, от страха бледный,\nВ темноте пред ним собака\n(Вы представьте Вани злость!)\nВаня стал; - шагнуть не может.\nГоре! малый я не сильный;\nЕсли сам земли могильной\nКрасногубый вурдалак.\nКто-то кость, ворча, грызёт.\nНа могиле гложет кость.\nПо могилам; вдруг он слышит, -\nРаз он позднею порой,\nСпотыкаясь, чуть бредёт\nСъест упырь меня совсем,\nТрусоват был Ваня бедный:\nЧрез кладбище шёл домой.\nЧто же? вместо вурдалака -\nЭто, верно, кости гложет\nЯ с молитвою не съем."
- testInputLines = splitOn "\n" testInput
- editDistance xs ys = table ! (m, n)
- where
- (m, n) = (length xs, length ys)
- x = array (1, m) (zip [1..] xs)
- y = array (1, n) (zip [1..] ys)
- table = array bnds [(ij, dist ij) | ij <- range bnds]
- bnds = ((0, 0), (m, n))
- dist (0, j) = j
- dist (i, 0) = i
- dist (i, j) = minimum [table ! (i - 1, j) + 1, table ! (i, j - 1) + 1,
- if x ! i == y ! j then table ! (i - 1, j - 1) else 1 + table ! (i - 1, j - 1)]
- transcription = transcription' . (' ':) . filter (`elem` ' ':'\n':'ё':['а'..'я']) . map toLower
- where
- rules = [
- ("ьё", "'jо"), ("ье", "'jэ"), ("ья", "'jа"), ("ью", "'jу"), ("ъё", "jо"), ("ъе", "jэ"), ("ъя", "jа"), (" ю", "jу"), (" ё", "jо"), (" е", "jэ"),
- (" я", "jа"), (" ю", "jу"), ("ё", "'о"), ("е", "'э"), ("я", "'а"), ("ю", "'у"), ("й", "j"), ("ъ", ""), ("ь", "'"), ("жи", "жы"), ("ши", "шы")
- ]
- transcription' s = foldl (\ s (src, dst) -> replace src dst s) s rules
- syllableCount = length . filter (`elem` "ёуеыаоэяию") . map toLower
- groupBySyllableCount = map (map fst) . groupBy ((==) `on` snd) . sortBy (compare `on` snd) . map (\ s -> (s, syllableCount s))
- transcriptionEndingLength = 5
- getRhymablePart = take transcriptionEndingLength . filter (`notElem` " ") . reverse . transcription
- orderByRhyme = filter (\ (s1, s2) -> s1 < s2) . rhymeMatcher
- where
- rhymeMatcher lines = findBestMatching (\ s1 s2 -> if s1 == s2 then 1000 else (editDistance `on` getRhymablePart) s1 s2) lines lines
- solve = concatGroups [] . reorder . map process . splitOn "\n"
- where
- process line = (line, getRhymablePart line, syllableCount line)
- groupLines = map (map (\ (x, _, _) -> x)) . sortBy (compare `on` length) . groupBy (\ (_, _, x1) (_, _, x2) -> x1 == x2) . sortBy (\ (_, _, x1) (_, _, x2) -> compare x2 x1)
- reorder = map reorderGroup . map (map reorderRhyme) . map orderByRhyme . groupLines
- reorderRhyme = id -- not implemented
- reorderGroup = id -- not implemented
- concatGroups acc [] = acc
- concatGroups acc (group:[]) = acc ++ (group >>= (\ (a, b) -> [a, b]))
- concatGroups acc (group1:group2:rest) = concatGroups (acc ++ (zip group1 group2 >>= (\ ((a, b), (c, d)) -> [a, c, b, d]))) rest
- main =
- hSetEncoding stdin utf8 >> hSetEncoding stdout utf8 >> getContents >>= mapM putStrLn . solve
- -- BestMatching.hs
- module BestMatching (findBestMatching) where
- data NetworkEdge = NetworkEdge { from :: Int, to :: Int, cost :: Int, capacity :: Int, flow :: Int }
- deriving (Show)
- infinity = 100000
- initNetwork distance xs ys partSize source sink part1Offset part2Offset =
- [0..partSize - 1] >>= (\ v -> [NetworkEdge source (part1Offset + v) 0 1 0, NetworkEdge (part2Offset + v) sink 0 1 0]
- ++ [NetworkEdge (part1Offset + v) (part2Offset + v') (distance (xs !! v) (ys !! v')) 1 0 | v' <- [0..partSize - 1]])
- >>= (\ e@(NetworkEdge x y d _ _) -> [e, NetworkEdge y x (-d) 0 0])
- maxExtraFlowOnPath result path i network
- | path !! i == -1 = result
- | otherwise = maxExtraFlowOnPath (min result $ capacity edge - flow edge) path (from edge) network
- where edge = network !! (path !! i)
- addFlowOnPath extraFlow path i network
- | path !! i == -1 = network
- | (path !! i) `mod` 2 == 0 =
- let (x, y:y':ys) = splitAt (path !! i) network in
- addFlowOnPath extraFlow path (from y) $ x ++ ((y { flow = flow y + extraFlow }):(y' { flow = flow y' - extraFlow }):ys)
- | otherwise =
- let (x, y':y:ys) = splitAt (path !! i - 1) network in
- addFlowOnPath extraFlow path (from y) $ x ++ (y' { flow = flow y' - extraFlow }):((y { flow = flow y + extraFlow }):ys)
- addExtraFlowOnPath path i network = addFlowOnPath (maxExtraFlowOnPath infinity path i network) path i network
- findShortestPathInResidualNetwork networkSize = findShortestPathInResidualNetwork' networkSize ([-1,-1..], 0:[infinity, infinity..]) networkSize
- where
- findShortestPathInResidualNetwork' 0 acc _ _ to _ = ((fst acc) !! to /= -1, take networkSize $ fst acc)
- findShortestPathInResidualNetwork' iteration acc networkSize from to network =
- findShortestPathInResidualNetwork' (iteration - 1) (foldl relax acc $ zip [0..] network) networkSize from to network
- relax acc@(result, distances) (i, edge)
- | flow edge >= capacity edge || distances !! (from edge) >= infinity || distances !! (to edge) <= (distances !! (from edge)) + cost edge = acc
- | otherwise =
- let (resPrev, res:resRest) = splitAt (to edge) result in
- let (distPrev, dist:distRest) = splitAt (to edge) distances in
- (resPrev ++ (i:resRest), distPrev ++ ((distances !! (from edge)) + (cost edge):distRest))
- findBestMatching distance xs ys
- | length xs /= length ys = error "Lengths should be equal"
- | otherwise = restoreAnswer $ addFlowWhilePossible True [-1, -1..] $ initNetwork distance xs ys partSize source sink part1Offset part2Offset
- where
- partSize = length xs
- source = 0
- sink = 1 + partSize * 2
- part1Offset = 1
- part2Offset = 1 + partSize
- networkSize = 2 + partSize * 2
- addFlowWhilePossible False _ network = network
- addFlowWhilePossible True path network =
- let (hasPath, nextPath) = findShortestPathInResidualNetwork networkSize source sink network in
- addFlowWhilePossible hasPath nextPath $ addExtraFlowOnPath path sink network
- restoreAnswer network = filter (\ (NetworkEdge f t _ _ fl) -> fl == 1 && f >= part1Offset && f < part1Offset + partSize && t >= part2Offset && t < part2Offset + partSize && f < t) network
- >>= (\ (NetworkEdge f t _ _ _) -> [(xs !! (f - part1Offset), ys !! (t - part2Offset))])
Advertisement
Add Comment
Please, Sign In to add comment