-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdijkstra.py
More file actions
70 lines (49 loc) · 1.75 KB
/
dijkstra.py
File metadata and controls
70 lines (49 loc) · 1.75 KB
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
import unittest
from itertools import izip
from graph import Graph
def dijkstra(graph, source):
assert isinstance(graph, Graph)
assert 0 <= source < len(graph)
marks = [None] * len(graph)
prev_vertex_marks = [None] * len(graph)
discovered = [False] * len(graph)
marks[source] = 0
v_from = source
while v_from >= 0:
discovered[v_from] = True
for v_to in graph[v_from]:
_relax(marks, prev_vertex_marks, v_from, v_to, graph.get_mark(v_from, v_to))
v_from = _find_min_undiscovered(marks, discovered)
# assert all(discovered), "Graph has stand-alone vertices"
return marks, prev_vertex_marks
def _find_min_undiscovered(marks, discovered):
assert len(marks) == len(discovered)
min_idx, min_mark = -1, None
for idx, (mark, discovered) in enumerate(izip(marks, discovered)):
if not discovered and mark is not None:
if min_mark is None or min_mark > mark:
min_idx = idx
min_mark = mark
return min_idx
def _relax(marks, prev_vertex_marks, v_from, v_to, weight):
new_mark = marks[v_from] + weight
if marks[v_to] is None or marks[v_to] > new_mark:
marks[v_to] = new_mark
prev_vertex_marks[v_to] = v_from
class TestCase(unittest.TestCase):
def test_simple(self):
graph = Graph(6)
graph.add(0, 1, 3)
graph.add(0, 2, 15)
graph.add(1, 2, 7)
graph.add(1, 3, 2)
graph.add(2, 4, 5)
graph.add(3, 2, 1)
graph.add(3, 5, 20)
graph.add(4, 3, 3)
graph.add(4, 5, 4)
marks, _ = dijkstra(graph, 0)
expected_marks = [0, 3, 6, 5, 11, 15]
self.assertListEqual(marks, expected_marks)
if __name__ == '__main__':
unittest.main()