1
+ '''
2
+ Purpose is to the find shortest path from all nodes to all other nodes, O(n^3).
3
+ Can be used with negative weights, however to check if it has negative cycles, bellman ford should prob. be used first.
4
+
5
+ Programmed by Aladdin Persson <aladdin.persson at hotmail dot com>
6
+ * 2019-03-08 Initial programming
7
+
8
+ '''
9
+
10
+ def load_graph (file_name ):
11
+ try :
12
+ with open (file_name ) as file :
13
+ line_list = file .readlines ()
14
+ file .close ()
15
+
16
+ except IOError :
17
+ raise IOError ("File does not exist" )
18
+
19
+ G = {int (line .split ()[0 ]): {(int (tup .split (',' )[0 ])): int (tup .split (',' )[1 ])
20
+ for tup in line .split ()[1 :] if tup } for line in line_list if line }
21
+
22
+ # If we have path set path else make value infinity
23
+ adjacency_matrix = [[G [i ][j ] if (i in G and j in G [i ]) else float ('inf' ) for j in range (1 , len (G ) + 1 )] for i in range (1 , len (G ) + 1 )]
24
+
25
+ # Make diagonal values all 0
26
+ for i in range (len (G )):
27
+ adjacency_matrix [i ][i ] = 0
28
+
29
+ # next will be matrix showing which path to take for the shortest path
30
+ next = [[j if adjacency_matrix [i ][j ] != float ('inf' ) else None for j in range (len (G ))] for i in range (len (G ))]
31
+
32
+ return adjacency_matrix , next
33
+
34
+ def floyd_warshall (adj_matrix , next ):
35
+ n = len (adj_matrix )
36
+ # make a copy of adj_matrix, dp will contain APSP (All-Path-Shortest-Path) solutions,
37
+ APSP = adj_matrix .copy ()
38
+
39
+ # Can we get a better path by going through node k?
40
+ for k in range (n ):
41
+ # Goal is to find path from i to j
42
+ for i in range (n ):
43
+ for j in range (n ):
44
+ # if distance from i to k, then k to j is less than distance i to j
45
+ if APSP [i ][k ] + APSP [k ][j ] < APSP [i ][j ]:
46
+ APSP [i ][j ] = APSP [i ][k ] + APSP [k ][j ]
47
+ next [i ][j ] = next [i ][k ]
48
+
49
+ # return APSP (All-Path-Shortest-Path) matrix
50
+ return APSP , next
51
+
52
+ def construct_path_to_take (next , start , end ):
53
+ go_through = start
54
+ path = [start ]
55
+
56
+ while next [go_through ][end ] != end :
57
+ go_through = next [go_through ][end ]
58
+ path .append (go_through )
59
+
60
+ path .append (end )
61
+
62
+ return path
63
+
64
+ if __name__ == '__main__' :
65
+ adj_matrix , next = load_graph ('test_graph.txt' )
66
+ APSP , next = floyd_warshall (adj_matrix , next )
67
+
68
+ print (f'The shortest paths are { APSP } ' )
69
+ print (f'The path to take is given by { next } ' )
70
+
71
+ path_to_take = construct_path_to_take (next , 0 , 3 )
72
+ print (path_to_take )
0 commit comments