summaryrefslogtreecommitdiff
path: root/80-89/84.hs
diff options
context:
space:
mode:
Diffstat (limited to '80-89/84.hs')
-rw-r--r--80-89/84.hs48
1 files changed, 48 insertions, 0 deletions
diff --git a/80-89/84.hs b/80-89/84.hs
new file mode 100644
index 0000000..1d2143b
--- /dev/null
+++ b/80-89/84.hs
@@ -0,0 +1,48 @@
+import qualified Data.Map as Map
+import Data.Map (Map)
+import Data.List (foldl', sortBy)
+import Control.Monad (foldM, mapM)
+
+data Graph a b = Graph [a] [(a, a, b)] deriving (Show, Eq)
+
+graph = Graph [1,2,3,4,5] [(1,2,12),(1,3,34),(1,5,78),(2,4,55),
+ (2,5,32),(3,4,61),(3,5,44),(4,5,93)]
+
+newElem :: Ord a => Map a a -> a -> Maybe (Map a a)
+findLead :: Ord a => Map a a -> a -> Maybe (Map a a, a)
+unionSet :: Ord a => Map a a -> a -> a -> Maybe (Map a a)
+
+newElem m v = Just (Map.insert v v m)
+findLead m v = do pv <- Map.lookup v m
+ if pv == v then return (m, v) else do
+ (m', v') <- findLead m pv
+ return (Map.adjust (\_ -> v') v m', v')
+unionSet m u v = do (m', lu) <- findLead m u
+ (m'', lv) <- findLead m' v
+ return (Map.adjust (\_ -> lv) lu m'')
+
+-- The above lines implement a monadic union-find-set, e.g:
+-- z = do m <- newElem Map.empty 1
+-- m1 <- newElem m 2
+-- m2 <- newElem m1 3
+-- m3 <- newElem m2 4
+-- m4 <- unionSet m3 1 2
+-- m5 <- unionSet m4 3 4
+-- m6 <- unionSet m5 2 3
+-- (m7, _) <- findLead m6 1
+-- return m7
+
+kruskal :: (Ord a, Ord b, Num b) => Graph a b -> Maybe b
+
+kruskal (Graph [] _) = Nothing
+kruskal (Graph v e) = span (sortBy (\(_, _, c) (_, _, c') -> c `compare` c') e)
+ (foldM (\acc u -> newElem acc u) Map.empty v) 0
+ where span [] comp0 cost = return cost
+ span ((u, v, c):es) comp0 cost =
+ do comp <- comp0
+ (comp', lu) <- findLead comp u
+ (comp'', lv) <- findLead comp' v
+ comp''' <- unionSet comp'' u v
+ let (compf, cost') = if lu == lv then (comp'', cost)
+ else (comp''', cost + c)
+ span es (return compf) cost'