-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmst.lisp
89 lines (80 loc) · 3.2 KB
/
mst.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
(defpackage :prim-mst
(:use :common-lisp)
(:export :prim))
(in-package :prim-mst)
;; find the vertex with minimum key value
(defun min-key (keys mst-set vertices)
(let ((min-value most-positive-fixnum)
(min-vertex nil))
(dolist (v vertices)
(when (and (not (gethash v mst-set))
(< (gethash v keys) min-value))
(setf min-value (gethash v keys))
(setf min-vertex v)))
min-vertex))
;; prims algorithm
(defun prim (graph &key (start-vertex nil))
"graph is a hash table where each key is a vertex and the value is a list of
(Vertex . Cost) pairs.
start-vertex is the vertex to start the algorithm"
(let* ((vertices (loop for k being the hash-keys of graph collect k))
(mst-set (make-hash-table :test 'equal))
(keys (make-hash-table :test 'equal))
(parents (make-hash-table :test 'equal))
(mst (make-hash-table :test 'equal)))
(dolist (v vertices)
(setf (gethash v keys) most-positive-fixnum)
(setf (gethash v parents) nil))
;; Choose the start vertex
(let ((start (or start-vertex (first vertices))))
(unless start
(error "Graph has no vertices"))
(setf (gethash start keys) 0))
;; Repeat for all vertices
(loop for i from 1 to (length vertices) do
(let ((u (min-key keys mst-set vertices)))
(when u
;; Add the picked vertex to MST set
(setf (gethash u mst-set) t)
;; If u has a parent, add the edge to the MST
(when (gethash u parents)
(setf (gethash u mst (gethash u parents))
(find (gethash u parents) (gethash (gethash u parents) graph)
:key #'car :test #'equal :key)))
(setf (gethash (gethash u parents) mst u)
(find u (gethash (gethash u parents) graph)
:key #'car :test #'equal)))
;; Update the key and parent of adjacent vertices
(dolist (adj (gethash u graph))
(let ((v (car adj))
(weight (cdr adj)))
(when (and (not (gethash v mst-set))
(< weight (gethash v keys)))
(setf (gethash v keys) weight)
(setf (gethash v parents) u))))))
;; Construct the MST as an adjacency list
(let ((mst-adj (make-hash-table :test 'equal)))
(maphash (lambda (child parent)
(push (cons child (gethash child graph)) (gethash parent mst-adj)))
parents)
mst-adj)))
;;; Example usage
(defun example ()
"Demonstrates Prim's algorithm with a sample graph."
(let ((graph (make-hash-table :test 'equal)))
;; Example graph:
;; A --2-- B
;; | \ |
;; 3 1 4
;; | \ |
;; C --5-- D
(setf (gethash "A" graph) '(("B" . 2) ("C" . 3) ("D" . 1)))
(setf (gethash "B" graph) '(("A" . 2) ("D" . 4)))
(setf (gethash "C" graph) '(("A" . 3) ("D" . 5)))
(setf (gethash "D" graph) '(("A" . 1) ("B" . 4) ("C" . 5)))
(let ((mst (prim graph :start-vertex "A")))
;; Print the MST
(format t "Minimum Spanning Tree:~%")
(maphash (lambda (vertex adjacents)
(format t "~a: ~a~%" vertex adjacents))
mst))))