diff --git a/03_dijkstra/LeastReachableCity.hs b/03_dijkstra/LeastReachableCity.hs deleted file mode 100644 index 3c6abaa..0000000 --- a/03_dijkstra/LeastReachableCity.hs +++ /dev/null @@ -1,75 +0,0 @@ -module LeastReachableCity(dijkstra, leastReachableCity) where - -import Types -import qualified Data.Map as Map -import qualified Data.Set as Set - --- Well, it's just a magic number, because it's too much hassle to implement type like "Len val | Infinity" --- TODO: get graph radius and use this number as infinity -infinity :: Len -infinity = 999999 :: Len - -leastReachableCity :: Graph -> Len -> (Point, Int) -leastReachableCity graph mileage = foldl (\(p, n) (p', n') -> - if n' < n then (p',n') - else (p, n)) - (-1, infinity) [(city, countReachableCities $ dijkstra city graph) | city <- Set.toList $ fst $ countVertices graph] where - countReachableCities :: Distances -> Int - countReachableCities distances = Map.foldl (\n val -> if (val <= mileage) && (val /= 0) then n + 1 else n) 0 distances - -dijkstra :: Point -> Graph -> Distances -dijkstra start graph = dijkstra' start graph visited_init to_visit_init distances_init where - -- Helper (so we don' need to call dijkstra initializing empty visited, to_visit etc) - dijkstra' :: Point -> Graph -> Vertices -> Vertices -> Distances -> Distances - dijkstra' start graph visited to_visit distances = if Set.null to_visit - then - distances - else - dijkstra' - (findMinNotVisited to_visit distances) - graph - (Set.insert start visited) - (Set.union (Set.delete start to_visit) $ findNotVisitedNeighbours graph visited start) - (updateDistances graph start distances) - -- Other - to_visit_init = (Set.insert start $ Set.empty :: Vertices) - distances_init = (infinityDistances start $ snd $ countVertices graph) - visited_init = (Set.empty :: Vertices) - -updateDistances :: Graph -> Point -> Distances -> Distances -updateDistances graph point distances = snd $ Map.foldrWithKey decideMin ((point, Map.findWithDefault (-1) point distances), Map.empty :: Distances) distances where - decideMin :: Point -> Len -> ((Point, Len), Distances) -> ((Point, Len), Distances) - decideMin p' l' ((p, l), dist) = if findDistance graph p p' + l < l' then - ((p, l), Map.insert p' (l + findDistance graph p p') dist) else - ((p, l), Map.insert p' l' dist) - -findDistance :: Graph -> Point -> Point -> Len -findDistance ((Node (a, b, len)) : graph) p p' = if ((a == p) && (b == p') || (b == p) && (a == p')) then len else findDistance graph p p' -findDistance _ _ _ = infinity - -findMinNotVisited :: Vertices -> Distances -> Point -findMinNotVisited to_visit distances = fst $ Set.foldl (\(p, l) p' -> case Map.lookup p' distances of - (Just l') -> if l' < l then - (p', l') - else (p,l)) - (-1, infinity) to_visit - -infinityDistances :: Point -> Int -> Distances -infinityDistances point n = Map.fromList $ (point, 0) : [(x, infinity) | x <- [1..n], x /= point] - -countVertices :: Graph -> (Vertices, Int) -countVertices graph = foldl f (Set.empty :: Vertices, 0) graph where - f :: (Vertices, Int) -> Node -> (Vertices, Int) - f (vertices, n) (Node (a, b, _)) = - let aIsNotMember = not $ Set.member a vertices - bIsNotMember = not $ Set.member b vertices in if (aIsNotMember && bIsNotMember) then (Set.insert a $ Set.insert b vertices, n + 2) - else if (aIsNotMember) then (Set.insert a vertices, n + 1) - else if (bIsNotMember) then (Set.insert b vertices, n + 1) - else (vertices, n) - -findNotVisitedNeighbours :: Graph -> Vertices -> Point -> Vertices -findNotVisitedNeighbours graph visited point = foldl f (Set.empty :: Vertices) graph where - f :: Vertices -> Node -> Vertices - f vertices (Node (a, b, _)) = if ((a == point) && (not $ Set.member b visited)) then Set.insert b vertices - else if ((b == point) && (not $ Set.member a visited)) then Set.insert a vertices - else vertices diff --git a/03_dijkstra/Types.hs b/03_dijkstra/Types.hs deleted file mode 100644 index 533feda..0000000 --- a/03_dijkstra/Types.hs +++ /dev/null @@ -1,13 +0,0 @@ -module Types where - -import qualified Data.Map as Map -import qualified Data.Set as Set - -type Point = Int -type Len = Int - -data Node = Node (Point, Point, Len) deriving Show -type Graph = [Node] - -type Distances = Map.Map Point Len -type Vertices = Set.Set Point diff --git a/03_dijkstra/data b/03_dijkstra/data deleted file mode 100644 index 9903946..0000000 --- a/03_dijkstra/data +++ /dev/null @@ -1,9 +0,0 @@ -4 - -1 2 10 -1 4 2 -1 3 3 -3 2 5 -2 4 6 -4 5 4 -5 3 1 diff --git a/03_dijkstra/main.hs b/03_dijkstra/main.hs deleted file mode 100644 index 8936dc7..0000000 --- a/03_dijkstra/main.hs +++ /dev/null @@ -1,46 +0,0 @@ -module Main where - -import System.IO -import System.Environment - -import qualified Data.Map as Map -import qualified Data.Set as Set - -import LeastReachableCity -import Types - -{- format of input file is: - - mileage - - from to len - - from to len - - ... - - where "from" and "to" are numbers of graph vertices, "len" is distance between them - - -} -main :: IO() -main = do - argv <- getArgs - - filename <- if not $ null argv then do - head <$> getArgs - else do - putStrLn "Usage: ./lrc [filename]\nNow defaulting to file \"data\"" - return "data" - - content <- readFile filename - let mileage = read $ head $ lines content :: Len - let graph = readGraph $ tail content - let (city, n) = leastReachableCity graph mileage - putStrLn $ "The least reachable city is " ++ (show city) ++ " (" ++ (show n) ++ " city/ies is/are reachable)" - -{- For parsing graph using content of the file -} -parseStrNode :: [String] -> Node -parseStrNode [a, b, c] = Node (p a, p b, l c) where - p x = read x :: Point - l x = read x :: Len - -readGraph :: String -> Graph -readGraph content = parse lst where - parse (x:xs) = if length ws == 3 then (parseStrNode ws) : (parse xs) else parse xs where - ws = words x - parse _ = [] - lst = lines content