NLinker icon

Задача №1005. Домой на электричках

NLinker | PRO | 10/16/19 01:32:49 PM UTC | 0 ⭐ | 12653 👁️ | Never ⏰ | []
Haskell |

25.97 KB

|

None

|

0 👍

/

0 👎

{-# LANGUAGE RecordWildCards     #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
{-# OPTIONS_GHC -fno-warn-unused-binds #-}
{-# OPTIONS_GHC -fno-warn-unused-matches #-}
 
----------------------
-- The solution for --
-- https://informatics.mccme.ru/moodle/mod/statements/view3.php?chapterid=1005#1
 
module Main where
 
import Control.Applicative (Applicative, pure, (<$>), (<*>))
import Control.Exception   (handle, throwIO)
import Control.Monad       (foldM, forM)
import Data.Char           (isSpace)
import Data.Foldable       (foldl')
import Data.Function       (on)
import Data.List           (sortBy)
import Data.Maybe          (mapMaybe, fromJust)
import Debug.Trace
import Prelude             hiding (exp, lookup, null)
import System.IO.Error     (isEOFError)
 
import qualified Data.ByteString.Char8 as BS
import qualified Data.Map              as M
import qualified Data.Set              as S
import qualified Prelude               as P (foldr, null)
 
-- http://informatics.mccme.ru/moodle/mod/statements/view3.php?chapterid=1005#1
type TimeTable = M.Map (Int, Int) Int
data Ctx = Ctx
  { n  :: Int -- total number of towns
  , e  :: Int -- destination
  , m  :: Int -- the number of routes
  , tt :: TimeTable -- time table for the trains
  } deriving (Eq, Show)
 
newtype Node = Node Int deriving (Eq, Ord, Show)
newtype Dist = Dist Int deriving (Eq, Ord, Show)
 
-- Graph is the nodes and adjacency lists for all nodes
data Graph = Graph
  { nodes :: S.Set Node
  , arcs  :: Arcs
  } deriving (Show)
 
type Arcs = M.Map Node [(Node, Dist)]
type Path = M.Map Node (Node, Dist)
type Explored = S.Set Node
type PrioQueue = PSQ Node Dist
 
main :: IO ()
main = do
  ctx <- parseCtx
  len <- calc ctx
  print len
 
ctx0 = Ctx
  { n = 5
  , e = 3
  , m = 4
  , tt = M.fromList
   [ ((1,1),5),((1,2),10)
   , ((2,2),10),((2,4),15)
   , ((3,2),35),((3,3),20),((3,4),17),((3,5),0)
   , ((4,1),2),((4,3),40),((4,4),45)
   ]
  }
 
-- result is -1
ctx1 = Ctx
  { n = 3
  , e = 2
  , m = 2
  , tt = M.fromList
   [ ((1,1),2),((1,2),20)
   , ((2,2),17),((2,3),23)
   ]
  }
 
--undefined
 
-- useful functions
-- mapMaybe :: (a -> Maybe b) -> [a] -> [b]
-- on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
-- compare :: Ord a => a -> a -> Ordering
-- curry :: ((a, b) -> c) -> a -> b -> c
 
calc :: (Monad m) => Ctx -> m Int
calc ctx@Ctx {..} = do
  -- use monad to make the syntax nicer
  g <- buildGraph ctx
  -- traceShowM g
  let col1 = buildCol ctx 1 -- all the nodes in the first column
  let nes = buildCol ctx e -- all the nodes in the column e
  if P.null col1 || P.null nes
    then return (-1)
      -- d0 = initial time delay
    else do
      let (x0, d0) = head col1
      let initial = Node x0
      path <- dijkstra g initial
      -- path is like
      --   fromList [ (Node 2, (Node 1, Dist 5)), (Node 7, (Node 2, Dist 0))]
      -- find the minimum distance for all nodes in column e, if reachable
      let ds = reachableDests path initial nes
      return $ if P.null ds
        then -1
        else d0 + minimum ds
 
buildGraph :: Monad m => Ctx -> m Graph
buildGraph ctx@Ctx{..} = do
  let nodes = S.fromList $ map Node [1 .. m * n]
  let arcs = buildArcs
  return $ Graph nodes arcs
  where
    buildArcs = do
      let mkEmpty x = (Node x, [] :: [(Node, Dist)])
      let arcs0 = M.fromList $ map mkEmpty [1 .. m * n]
      let arcs1 = foldl' updateArcsR arcs0 [1 .. m]
      let arcs2 = foldl' updateArcsC arcs1 [1 .. n]
      arcs2
    -- go by rows and update arcs
    updateArcsR as i = foldl' updateArcR as $ diffs $ buildRow ctx i
    -- go by columns and update arcs
    updateArcsC as j = foldl' updateArcC as $ diffs $ buildCol ctx j
 
reachableDests :: Path -> Node -> [(Int, t)] -> [Int]
reachableDests path initial = mapMaybe $ calcDistance path initial . fstNode
  where
    fstNode (x, _) = Node x
 
-- path, initial node, final node
calcDistance :: Path -> Node -> Node -> Maybe Int
calcDistance path initial = calcD 0
  where
    calcD acc x1 =
      if x1 == initial
        then Just acc
        else case M.lookup x1 path of
          Nothing          -> Nothing
          Just (x, Dist d) -> calcD (acc + d) x
 
 
-- update arcs using horizontal cell pair
updateArcR as (n1, n2, d) =
  let n1s = fromJust $ M.lookup n1 as
  in M.insert n1 ((n2, d) : n1s) as
 
-- update arcs using vertical cell pair
updateArcC as (n1, n2, d) =
    if d == Dist 0 then
      -- insert two arcs, back and forward
      let n1s = fromJust $ M.lookup n1 as in
      let n2s = fromJust $ M.lookup n2 as in
      M.insert n1 ((n2, d) : n1s) $
        M.insert n2 ((n1, d) : n2s) as
    else
      let n1s = fromJust $ M.lookup n1 as in
      M.insert n1 ((n2, d) : n1s) as
 
-- assumes the list is sorted by weights
-- [((9,15),(14,17)),((14,17),(19,45))] -> [(Node 9,Node 14,Dist 2),(Node 14,Node 19,Dist 28)]
diffs :: [(Int, Int)] -> [(Node, Node, Dist)]
diffs xs =
  let diffPair (n1, w1) (n2, w2) = (Node n1, Node n2, Dist $ w2 - w1)
  in zipWith diffPair xs (tail xs)
 
-- return absolute node number
-- e.g. for matrix 4x5
-- cell (4,2) will be 17
-- cell (3,5) will be 15
cell :: Ctx -> Int -> Int -> Int
cell ctx i j = (i - 1) * n ctx + j
 
buildRow :: Ctx -> Int -> [(Int, Int)]
buildRow ctx@Ctx{..} i =
  let select j = (\w -> (cell ctx i j, w)) `fmap` M.lookup (i, j) tt
  in sortBy (compare `on` snd) $ mapMaybe select [1 .. n]
 
buildCol :: Ctx -> Int -> [(Int, Int)]
buildCol ctx@Ctx{..} j =
  let select i = (\w -> (cell ctx i j, w)) `fmap` M.lookup (i, j) tt
  in sortBy (compare `on` snd) $ mapMaybe select [1 .. m]
 
-------------------------------------------------------
--------------- Dijkstra Algorithm---------------------
-------------------------------------------------------
-- some test for the algorithm
kickDijkstra :: IO ()
kickDijkstra = do
  let initial = Node 1
  g <- loadGraph "dijkstra.txt"
  traceShowM g
  p <- dijkstra g initial
  traceShowM p
 
infinity :: Dist
infinity = Dist 999999999
 
dijkstra :: (Monad m) => Graph -> Node -> m Path
dijkstra g initial = do
  let rest = S.delete initial $ nodes g
  let mkInf x = x :-> infinity
  let heap = fromList $ (initial :-> Dist 0) : map mkInf (S.toList rest)
  let path = M.singleton initial (initial, Dist 0) :: Path
  mainLoop g heap S.empty M.empty
 
mainLoop :: (Monad m) => Graph -> PrioQueue -> Explored -> Path -> m Path
mainLoop g heap exp path = do
  let bind' = findMin heap
  case bind' of
    Nothing ->
      return path
    Just (mn :-> md) ->
      -- warning: causes (Node 14,(Node 15,Dist 17)) which is wrong
      -- if md == infinity then return path else
      do
        -- found minimal node with the distance
        let heap1 = deleteMin heap
        let arcs' = M.lookup mn (arcs g)
        let (heap2, path2) = case arcs' of
              -- lookup into arcs in g for min node failed
              -- Nothing -> error "inconsistent data"
              Nothing -> (heap1, path)
              Just as ->
                -- skip already explored nodes
                let as1 = filter (\(n, _) -> S.notMember n exp) as in
                (updateHeap heap1 md as1, updatePath path mn as1)
        let exp2 = S.insert mn exp
        -- traceShowM $ "node=(" ++ show mn ++ "," ++ show md ++ "\theap2=" ++ show heap2
        mainLoop g heap2 exp2 path2
 
updatePath :: Path -> Node -> [(Node, Dist)] -> Path
updatePath path minNode = foldl' yo path
  where
    yo :: Path -> (Node, Dist) -> Path
    yo p (n, d) = M.insert n (minNode, d) p
 
-- updateHeap takes minDist to newly explored node,
-- and list of all edges from the new node
updateHeap :: PrioQueue -> Dist -> [(Node, Dist)] -> PrioQueue
updateHeap heap minDist = foldl' go heap
  where
    -- e is the old distance was in the queue
    up d e =
      let Dist md = minDist in
      let Dist nd = d in
      min e $ Dist (md + nd)
    go :: PrioQueue -> (Node, Dist) -> PrioQueue
    go h (n, d) = adjust (up d) n h
 
-- Example file
--1 2:10    3:20
--2 4:15    5:50
--3 4:30
--4 5:30
--5 6:5
--6 7:2
--7
loadGraph :: String -> IO Graph
loadGraph path = do
  ls <- (map (BS.split '\t') . BS.lines) `fmap` BS.readFile path
  let g = Graph S.empty M.empty
  foldM processLine g ls
  where
    conv (x, y) = (Node x, Dist y)
    processLine :: (Monad m) => Graph -> [BS.ByteString] -> m Graph
    processLine g (x:xs) = do
      let an = Node $ convert x
      let as = map (conv . splitter) xs
      let updateArcs old (n, d) =
            case M.lookup an old of
              Just ns -> M.insert an ((n, d):ns) old
              Nothing -> M.insert an [] old
      let updateDists old (n, d) = M.insert (an, n) d old
      let nodes1 = S.insert an (nodes g)
      let arcs1 = foldl' updateArcs (M.insert an [] $ arcs g) as
      return $ Graph nodes1 arcs1
    processLine g [] = error "processLine"
 
convert :: BS.ByteString -> Int
convert = maybe (error "can't read Int") fst . BS.readInt
 
splitter :: BS.ByteString -> (Int, Int)
splitter c = (convert x, convert y)
  where
    (x:y:_) = BS.split ':' c
 
-----------------------------------------------------------
------------------- stuff for parsing ---------------------
-----------------------------------------------------------
getWord :: IO String
getWord =
  handle handleEOF $ do
    c <- getChar
    if isSpace c
      then return []
      else (c :) <$> getWord
  where
    handleEOF e =
      if isEOFError e
        then return []
        else throwIO e
 
readWord :: Read a => IO a
readWord = getWord >>= readIO
 
readList :: Read a => String -> [a]
readList = map read . words
 
-- carry the route number
parseRoute :: Int -> IO (Int, [(Int,Int)])
parseRoute ri = do
  (ki :: Int) <- readWord
  stops <-
    forM [1 .. ki] $ \_ -> do
      x <- readWord
      y <- readWord
      return (x, y)
  return (ri, stops)
 
-- example input
--5 3 4
--2 1 5 2 10
--2 2 10    4 15
--4 2 35    3 20    4 17    5 0
--3 1 2 3 40    4 45
parseCtx :: IO Ctx
parseCtx = do
  n <- readWord
  e <- readWord
  m <- readWord
  rawTts <- mapM parseRoute [1 .. m]
  let tt = foldl' updateTt M.empty rawTts
  return Ctx {..}
  where
    -- updateTt :: TimeTable -> (Int, [(Int, Int)]) -> TimeTable
    updateTt tt (ri, stops) = foldl' (updateTtRow ri) tt stops
    -- updateTtRow :: Int -> TimeTable -> (Int, Int) -> TimeTable
    updateTtRow ri tt (i, t) = M.insert (ri, i) t tt
 
 
-------------------------------------------------------
--------------- Priority Queue ------------------------
-------------------------------------------------------
-- the priority queue is adapted from
-- http://hackage.haskell.org/package/PSQueue-1.1/docs/src/Data-PSQueue.html
 
-- | @k :-> p@ binds the key @k@ with the priority @p@.
data Binding k p = k :-> p deriving (Eq, Ord, Show, Read)
 
infix 0 :->
 
key  :: Binding k p -> k
key  (k :-> _) =  k
 
prio :: Binding k p -> p
prio (_ :-> p) =  p
 
data PSQ k p = Void | Winner k p (LTree k p) k
 
instance (Show k, Show p, Ord k, Ord p) => Show (PSQ k p) where
  show = show . toAscList
  --show Void = "[]"
  --show (Winner k1 p lt k2) = "Winner "++show k1++" "++show p++" ("++show lt++") "++show k2
 
-- | /O(1)/ The number of bindings in a queue.
size :: PSQ k p -> Int
size Void              = 0
size (Winner _ _ lt _) = 1 + size' lt
 
-- | /O(1)/ True if the queue is empty.
null :: PSQ k p -> Bool
null Void        = True
null (Winner {}) = False
 
-- | /O(log n)/ The priority of a given key, or Nothing if the key is not
-- bound.
lookup :: (Ord k, Ord p) => k -> PSQ k p -> Maybe p
lookup k q =
  case tourView q of
    Null -> fail "PSQueue.lookup: Empty queue"
    Single k' p
      | k == k'   -> return p
      | otherwise -> fail "PSQueue.lookup: Key not found"
    tl `Play` tr
      | k <= maxKey tl -> lookup k tl
      | otherwise      -> lookup k tr
 
empty :: (Ord k, Ord p) => PSQ k p
empty = Void
 
-- | O(1) Build a queue with one binding.
singleton :: (Ord k, Ord p) => k -> p -> PSQ k p
singleton k p =  Winner k p Start k
 
-- | /O(log n)/ Insert a binding into the queue.
insert :: (Ord k, Ord p) => k -> p -> PSQ k p -> PSQ k p
insert k p q =
  case tourView q of
    Null -> singleton k p
    Single k' p' ->
      case compare k k' of
        LT -> singleton k  p  `play` singleton k' p'
        EQ -> singleton k  p
        GT -> singleton k' p' `play` singleton k  p
    tl `Play` tr
      | k <= maxKey tl -> insert k p tl `play` tr
      | otherwise      -> tl `play` insert k p tr
 
-- | /O(log n)/ Remove a binding from the queue.
delete :: (Ord k, Ord p) => k -> PSQ k p -> PSQ k p
delete k q =
  case tourView q of
    Null -> empty
    Single k' p
      | k == k'   -> empty
      | otherwise -> singleton k' p
    tl `Play` tr
      | k <= maxKey tl -> delete k tl `play` tr
      | otherwise      -> tl `play` delete k tr
 
-- | /O(log n)/ Adjust the priority of a key.
adjust ::  (Ord p, Ord k) => (p -> p) -> k -> PSQ k p -> PSQ k p
adjust f = adjustWithKey (\_ p -> f p)
 
-- | /O(log n)/ Adjust the priority of a key.
adjustWithKey :: (Ord k, Ord p) => (k -> p -> p) -> k -> PSQ k p -> PSQ k p
adjustWithKey f k q =
  case tourView q of
    Null -> empty
    Single k' p
      | k == k'   -> singleton k' (f k p)
      | otherwise -> singleton k' p
    tl `Play` tr
      | k <= maxKey tl -> adjustWithKey f k tl `unsafePlay` tr
      | otherwise      -> tl `unsafePlay` adjustWithKey f k tr
 
-- | /O(log n)/ The expression (@update f k q@) updates the
-- priority @p@ bound @k@ (if it is in the queue). If (@f p@) is 'Nothing',
-- the binding is deleted. If it is (@'Just' z@), the key @k@ is bound
-- to the new priority @z@.
 
update :: (Ord k, Ord p) => (p -> Maybe p) -> k -> PSQ k p -> PSQ k p
update f = updateWithKey (\_ p -> f p)
 
-- | /O(log n)/. The expression (@updateWithKey f k q@) updates the
-- priority @p@ bound @k@ (if it is in the queue). If (@f k p@) is 'Nothing',
-- the binding is deleted. If it is (@'Just' z@), the key @k@ is bound
-- to the new priority @z@.
 
updateWithKey :: (Ord k, Ord p) => (k -> p -> Maybe p) -> k -> PSQ k p -> PSQ k p
updateWithKey f k q =
  case tourView q of
    Null -> empty
    Single k' p
      | k==k' -> case f k p of
                  Nothing -> empty
                  Just p' -> singleton k p'
      | otherwise -> singleton k' p
    tl `Play` tr
      | k <= maxKey tl -> updateWithKey f k tl `unsafePlay` tr
      | otherwise      -> tl `unsafePlay` updateWithKey f k tr
 
-- | /O(n)/ The keys of a priority queue
keys :: (Ord k, Ord p) => PSQ k p -> [k]
keys = map key . toList
 
-- | /O(n log n)/ Build a queue from a list of bindings.
fromList :: (Ord k, Ord p) => [Binding k p] -> PSQ k p
fromList = P.foldr (\(k:->p) q -> insert k p q) empty
 
-- | /O(n)/ Build a queue from a list of bindings in order of
-- ascending keys. The precondition that the keys are ascending is not checked.
fromAscList :: (Ord k, Ord p) => [Binding k p] -> PSQ k p
fromAscList = fromDistinctAscList . stripEq
  where stripEq []     = []
        stripEq (x:xs) = stripEq' x xs
        stripEq' x' []     = [x']
        stripEq' x' (x:xs)
          | x' == x   = stripEq' x' xs
          | otherwise = x' : stripEq' x xs
 
-- | /O(n)/ Build a queue from a list of distinct bindings in order of
-- ascending keys. The precondition that keys are distinct and ascending is not checked.
fromDistinctAscList :: (Ord k, Ord p) => [Binding k p] -> PSQ k p
fromDistinctAscList = foldm unsafePlay empty . map (\(k:->p) -> singleton k p)
 
-- Folding a list in a binary-subdivision scheme.
foldm :: (a -> a -> a) -> a -> [a] -> a
foldm f e x
  | P.null  x             = e
  | otherwise             = fst (rek (length x) x)
  where
    rek 1 (a : as)    = (a, as)
    rek n as          = (a1 `f` a2, as2)
      where
        m         = n `div` 2
        (a1, as1) = rek (n - m) as
        (a2, as2) = rek m       as1
 
-- | /O(n)/ Convert a queue to a list.
toList :: (Ord k, Ord p) => PSQ k p -> [Binding k p]
toList = toAscList
 
-- | /O(n)/ Convert a queue to a list in ascending order of keys.
toAscList :: (Ord k, Ord p) => PSQ k p -> [Binding k p]
toAscList q  = seqToList (toAscLists q)
 
toAscLists :: (Ord k, Ord p) => PSQ k p -> Sequ (Binding k p)
toAscLists q = case tourView q of
  Null         -> emptySequ
  Single k p   -> singleSequ (k :-> p)
  tl `Play` tr -> toAscLists tl <> toAscLists tr
 
-- | /O(n)/ Convert a queue to a list in descending order of keys.
toDescList :: (Ord k, Ord p) => PSQ k p -> [ Binding k p ]
toDescList q = seqToList (toDescLists q)
 
toDescLists :: (Ord k, Ord p) => PSQ k p -> Sequ (Binding k p)
toDescLists q = case tourView q of
  Null         -> emptySequ
  Single k p   -> singleSequ (k :-> p)
  tl `Play` tr -> toDescLists tr <> toDescLists tl
 
 
-- | /O(1)/ The binding with the lowest priority.
findMin :: (Ord k, Ord p) => PSQ k p -> Maybe (Binding k p)
findMin Void             = Nothing
findMin (Winner k p t m) = Just (k :-> p)
 
-- | /O(log n)/ Remove the binding with the lowest priority.
deleteMin :: (Ord k, Ord p) => PSQ k p -> PSQ k p
deleteMin Void             = Void
deleteMin (Winner k p t m) = secondBest t m
 
-- | /O(log n)/ Retrieve the binding with the least priority, and the rest of
-- the queue stripped of that binding.
minView :: (Ord k, Ord p) => PSQ k p -> Maybe (Binding k p, PSQ k p)
minView Void             = Nothing
minView (Winner k p t m) = Just ( k :-> p , secondBest t m )
 
secondBest :: (Ord k, Ord p) => LTree k p -> k -> PSQ k p
secondBest Start _m                  = Void
secondBest (LLoser _ k p tl m tr) m' = Winner k p tl m `play` secondBest tr m'
secondBest (RLoser _ k p tl m tr) m' = secondBest tl m `play` Winner k p tr m'
 
 
-- | /O(r(log n - log r)/ @atMost p q@ is a list of all the bindings in @q@ with
-- priority less than @p@, in order of ascending keys.
-- Effectively,
-- @  atMost p' q = filter (\\(k:->p) -> p<=p') . toList  @
atMost :: (Ord k, Ord p) => p -> PSQ k p -> [Binding k p]
atMost pt q = seqToList (atMosts pt q)
 
atMosts :: (Ord k, Ord p) => p -> PSQ k p -> Sequ (Binding k p)
atMosts _pt Void  = emptySequ
atMosts pt (Winner k p t _) =  prune k p t
  where
  prune _k _p _t
    | p > pt         = emptySequ
    | otherwise      = traverse k p t
  traverse _k _p Start                     = singleSequ (k :-> p)
  traverse _k _p (LLoser _ k' p' tl _m tr) = prune k' p' tl <> traverse k p tr
  traverse _k _p (RLoser _ k' p' tl _m tr) = traverse k p tl <> prune k' p' tr
 
-- | /O(r(log n - log r))/ @atMostRange p (l,u) q@ is a list of all the bindings in
-- @q@ with a priority less than @p@ and a key in the range @(l,u)@ inclusive.
-- Effectively,
-- @ atMostRange p' (l,u) q = filter (\\(k:->p) -> l<=k && k<=u ) . 'atMost' p' @
atMostRange :: (Ord k, Ord p) => p -> (k, k) -> PSQ k p -> [Binding k p]
atMostRange pt (kl, kr) q = seqToList (atMostRanges pt (kl, kr) q)
 
atMostRanges :: (Ord k, Ord p) => p -> (k, k) -> PSQ k p -> Sequ (Binding k p)
 
atMostRanges _pt _range Void = emptySequ
atMostRanges pt range@(kl, kr) (Winner k p t _) = prune k p t
  where
  prune _k _p _t
    | p > pt    = emptySequ
    | otherwise = traverse k p t
  traverse _k _p Start
    | k `inrange` range = singleSequ (k :-> p)
    | otherwise         = emptySequ
  traverse _k _p (LLoser _ k' p' tl m tr) =
    guard (kl <= m) (prune k' p' tl) <> guard (m <= kr) (traverse k p tr)
  traverse _k _p (RLoser _ k' p' tl m tr) =
    guard (kl <= m) (traverse k p tl) <> guard (m <= kr) (prune k' p' tr)
 
inrange :: (Ord a) => a -> (a, a) -> Bool
a `inrange` (l, r)  =  l <= a && a <= r
 
------- Internals -----
 
type Size = Int
data LTree k p = Start
               | LLoser {-# UNPACK #-}!Size !k !p (LTree k p) !k (LTree k p)
               | RLoser {-# UNPACK #-}!Size !k !p (LTree k p) !k (LTree k p)
 
size' :: LTree k p -> Size
size' Start                = 0
size' (LLoser s _ _ _ _ _) = s
size' (RLoser s _ _ _ _ _) = s
 
left, right :: LTree a b -> LTree a b
 
left  Start                  =  error "left: empty loser tree"
left  (LLoser _ _ _ tl _ _ ) =  tl
left  (RLoser _ _ _ tl _ _ ) =  tl
 
right Start                  =  error "right: empty loser tree"
right (LLoser _ _ _ _  _ tr) =  tr
right (RLoser _ _ _ _  _ tr) =  tr
 
maxKey :: PSQ k p -> k
maxKey Void                =  error "maxKey: empty queue"
maxKey (Winner _k _p _t m) =  m
 
lloser, rloser :: k -> p -> LTree k p -> k -> LTree k p -> LTree k p
lloser k p tl m tr =  LLoser (1 + size' tl + size' tr) k p tl m tr
rloser k p tl m tr =  RLoser (1 + size' tl + size' tr) k p tl m tr
 
--balance factor
omega :: Int
omega = 4
 
lbalance, rbalance ::
  (Ord k, Ord p) => k-> p -> LTree k p -> k -> LTree k p -> LTree k p
 
lbalance k p l m r
  | size' l + size' r < 2     = lloser        k p l m r
  | size' r > omega * size' l = lbalanceLeft  k p l m r
  | size' l > omega * size' r = lbalanceRight k p l m r
  | otherwise               = lloser        k p l m r
 
rbalance k p l m r
  | size' l + size' r < 2     = rloser        k p l m r
  | size' r > omega * size' l = rbalanceLeft  k p l m r
  | size' l > omega * size' r = rbalanceRight k p l m r
  | otherwise               = rloser        k p l m r
 
lbalanceLeft  k p l m r
  | size' (left r) < size' (right r) = lsingleLeft  k p l m r
  | otherwise                      = ldoubleLeft  k p l m r
 
lbalanceRight k p l m r
  | size' (left l) > size' (right l) = lsingleRight k p l m r
  | otherwise                      = ldoubleRight k p l m r
 
rbalanceLeft  k p l m r
  | size' (left r) < size' (right r) = rsingleLeft  k p l m r
  | otherwise                      = rdoubleLeft  k p l m r
 
rbalanceRight k p l m r
  | size' (left l) > size' (right l) = rsingleRight k p l m r
  | otherwise                      = rdoubleRight k p l m r
 
lsingleLeft k1 p1 t1 m1 (LLoser _ k2 p2 t2 m2 t3)
  | p1 <= p2  = lloser k1 p1 (rloser k2 p2 t1 m1 t2) m2 t3
  | otherwise = lloser k2 p2 (lloser k1 p1 t1 m1 t2) m2 t3
lsingleLeft _ _ _ _ Start = error "lsingleLeft"
 
lsingleLeft k1 p1 t1 m1 (RLoser _ k2 p2 t2 m2 t3) =
  rloser k2 p2 (lloser k1 p1 t1 m1 t2) m2 t3
 
rsingleLeft k1 p1 t1 m1 (LLoser _ k2 p2 t2 m2 t3) =
  rloser k1 p1 (rloser k2 p2 t1 m1 t2) m2 t3
rsingleLeft _ _ _ _ Start = error "rsingleLeft"
 
rsingleLeft k1 p1 t1 m1 (RLoser _ k2 p2 t2 m2 t3) =
  rloser k2 p2 (rloser k1 p1 t1 m1 t2) m2 t3
 
lsingleRight k1 p1 (LLoser _ k2 p2 t1 m1 t2) m2 t3 =
  lloser k2 p2 t1 m1 (lloser k1 p1 t2 m2 t3)
lsingleRight _ _ Start _ _ = error "lsingleRight"
 
lsingleRight k1 p1 (RLoser _ k2 p2 t1 m1 t2) m2 t3 =
  lloser k1 p1 t1 m1 (lloser k2 p2 t2 m2 t3)
 
rsingleRight k1 p1 (LLoser _ k2 p2 t1 m1 t2) m2 t3 =
  lloser k2 p2 t1 m1 (rloser k1 p1 t2 m2 t3)
rsingleRight k1 p1 Start m2 t3 = error "rsingleRight"
 
rsingleRight k1 p1 (RLoser _ k2 p2 t1 m1 t2) m2 t3
  | p1 <= p2  = rloser k1 p1 t1 m1 (lloser k2 p2 t2 m2 t3)
  | otherwise = rloser k2 p2 t1 m1 (rloser k1 p1 t2 m2 t3)
 
ldoubleLeft k1 p1 t1 m1 (LLoser _ k2 p2 t2 m2 t3) =
  lsingleLeft k1 p1 t1 m1 (lsingleRight k2 p2 t2 m2 t3)
ldoubleLeft k1 p1 t1 m1 Start = error "ldoubleLeft"
 
ldoubleLeft k1 p1 t1 m1 (RLoser _ k2 p2 t2 m2 t3) =
  lsingleLeft k1 p1 t1 m1 (rsingleRight k2 p2 t2 m2 t3)
 
ldoubleRight k1 p1 (LLoser _ k2 p2 t1 m1 t2) m2 t3 =
  lsingleRight k1 p1 (lsingleLeft k2 p2 t1 m1 t2) m2 t3
ldoubleRight k1 p1 Start m2 t3 = error "ldoubleRight"
 
ldoubleRight k1 p1 (RLoser _ k2 p2 t1 m1 t2) m2 t3 =
  lsingleRight k1 p1 (rsingleLeft k2 p2 t1 m1 t2) m2 t3
 
rdoubleLeft k1 p1 t1 m1 (LLoser _ k2 p2 t2 m2 t3) =
  rsingleLeft k1 p1 t1 m1 (lsingleRight k2 p2 t2 m2 t3)
rdoubleLeft k1 p1 t1 m1 Start = error "rdoubleLeft"
 
rdoubleLeft k1 p1 t1 m1 (RLoser _ k2 p2 t2 m2 t3) =
  rsingleLeft k1 p1 t1 m1 (rsingleRight k2 p2 t2 m2 t3)
 
rdoubleRight k1 p1 (LLoser _ k2 p2 t1 m1 t2) m2 t3 =
  rsingleRight k1 p1 (lsingleLeft k2 p2 t1 m1 t2) m2 t3
rdoubleRight k1 p1 Start m2 t3 = error "rdoubleRight"
 
rdoubleRight k1 p1 (RLoser _ k2 p2 t1 m1 t2) m2 t3 =
  rsingleRight k1 p1 (rsingleLeft k2 p2 t1 m1 t2) m2 t3
 
play :: (Ord k, Ord p) => PSQ k p -> PSQ k p -> PSQ k p
 
Void `play` t' = t'
t `play` Void  = t
 
Winner k p t m  `play`  Winner k' p' t' m'
  | p <= p'   = Winner k  p  (rbalance k' p' t m t') m'
  | otherwise = Winner k' p' (lbalance k  p  t m t') m'
 
unsafePlay :: (Ord k, Ord p) => PSQ k p -> PSQ k p -> PSQ k p
 
Void `unsafePlay` t' =  t'
t `unsafePlay` Void  =  t
 
Winner k p t m  `unsafePlay`  Winner k' p' t' m'
  | p <= p'   = Winner k  p  (rbalance k' p' t m t') m'
  | otherwise = Winner k' p' (lbalance k  p  t m t') m'
 
data TourView k p = Null | Single k p | PSQ k p `Play` PSQ k p
 
tourView :: (Ord k) => PSQ k p -> TourView k p
 
tourView Void                  =  Null
tourView (Winner k p Start _m) =  Single k p
 
tourView (Winner k p (RLoser _ k' p' tl m tr) m') =
  Winner k  p  tl m `Play` Winner k' p' tr m'
 
tourView (Winner k p (LLoser _ k' p' tl m tr) m') =
  Winner k' p' tl m `Play` Winner k  p  tr m'
 
-- Hughes's efficient sequence type --
 
emptySequ  :: Sequ a
singleSequ :: a -> Sequ a
(<>)       :: Sequ a -> Sequ a -> Sequ a
seqFromList   :: [a] -> Sequ a
seqFromListT  :: ([a] -> [a]) -> Sequ a
seqToList     :: Sequ a -> [a]
 
infixr 5 <>
 
newtype Sequ a  =  Sequ ([a] -> [a])
 
emptySequ = Sequ id
singleSequ a = Sequ (\as -> a : as)
Sequ x1 <> Sequ x2 = Sequ (x1 . x2)
seqFromList as = Sequ (\as' -> as ++ as')
seqFromListT = Sequ
seqToList (Sequ x) = x []
 
instance Show a => Show (Sequ a) where
    showsPrec d a = showsPrec d (seqToList a)
 
guard :: Bool -> Sequ a -> Sequ a
guard False _as = emptySequ
guard True  as  = as
 
 
-- ---------------------------------------------------------------------------
-- Identity instances for Functor and Monad
 
newtype Identity a = Identity { runIdentity :: a }
 
instance Functor Identity where
    fmap f m = Identity (f (runIdentity m))
 
instance Applicative Identity where
    pure = Identity
    (<*>) (Identity f) (Identity a) = Identity (f a)
 
instance Monad Identity where
    return = Identity
    m >>= k  = k (runIdentity m)

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎