Skip to content

Commit cd64aff

Browse files
committed
Dijkstra
1 parent 441f02d commit cd64aff

File tree

1 file changed

+28
-4
lines changed

1 file changed

+28
-4
lines changed

17.graph.hs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import Data.Map qualified as M
55
import Data.Set qualified as S
6-
import Data.Maybe (fromJust)
6+
import Data.Maybe (fromJust, fromMaybe)
77
import Data.Sequence (Seq(..), fromList, (><))
88

99
main :: IO ()
@@ -14,7 +14,7 @@ main = interact $ unlines . demo . parse
1414
dbfs grid = bfs grid (0, 0) (visitor "bfs")
1515
dsp grid = let end = maxNode grid
1616
(r, zs) = dijkstra grid (0, 0) end (visitor "shortest-path")
17-
in zs ++ ["shortest-path result " ++ show r]
17+
in zs ++ ["shortest-path result " ++ (show $ fromMaybe (-1) r)]
1818

1919
type Node = (Int, Int)
2020
data Grid a = Grid { items :: M.Map Node a, maxNode :: Node } deriving Show
@@ -52,6 +52,30 @@ bfs grid@Grid { items } start visitor = go (Empty :|> start) S.empty
5252
go (xs :|> x) seen = visit x : go ys (S.insert x seen)
5353
where ys = (fromList $ neighbours grid x) >< xs
5454

55+
-- For our example, the weight of the edge between u and v is the value
56+
-- at v. But this can be any arbitrary function or input data.
57+
distance :: Grid Int -> Node -> Node -> Int
58+
distance Grid { items } u v = fromJust $ M.lookup v items
59+
5560
-- Find the shortest path from start, to end, using Dijkstra's algorithm.
56-
dijkstra :: Grid a -> Node -> Node -> (Node -> a -> b) -> (Int, [b])
57-
dijkstra grid@Grid { items } start end visitor = (0, [])
61+
dijkstra :: Grid Int -> Node -> Node -> (Node -> Int -> b) -> (Maybe Int, [b])
62+
dijkstra grid@Grid { items } start end visitor = go (M.singleton start 0) S.empty
63+
where
64+
visit x = let item = fromJust $ M.lookup x items in visitor x item
65+
next ds seen = (M.lookupMin $ M.withoutKeys ds seen)
66+
go ds seen = case next ds seen of
67+
Nothing -> (Nothing, [])
68+
Just (u, du)
69+
| u == end -> (M.lookup u ds, [visit u])
70+
| otherwise ->
71+
let v = visit u
72+
seen' = S.insert u seen
73+
ds' = foldl (relax u du) ds (neighbours grid u)
74+
(d', vs) = go ds' seen'
75+
in (d', v : vs)
76+
77+
relax :: Node -> Int -> M.Map Node Int -> Node -> M.Map Node Int
78+
relax u du ds v = let d = distance grid u v in case M.lookup v ds of
79+
Just dv | dv < du + d -> ds
80+
_ -> M.insert v (du + d) ds
81+

0 commit comments

Comments
 (0)