4
4
# to all other vertices in weighted graph.
5
5
# Runtime O(V*E)
6
6
7
+ from typing import Set , Dict , List , Tuple
8
+
9
+
7
10
class Graph :
8
- def __init__ (self ):
9
- self .vertices : list = []
10
- self .edges : list = []
11
- self .distance : dict = {}
12
- self .prev : dict = {}
13
-
14
- def add_vertex (self , label : str ):
15
- self .vertices .append (label )
16
- self .distance [label ] = None
11
+
12
+
13
+ def __init__ (self ) -> None :
14
+ self .vertices :Set [str ] = set ()
15
+ self .edges :List [Tuple [str , str , int ]] = list ()
16
+ self .prev :Dict [str , str ] = dict ()
17
+ self .distances :Dict [str , int ] = dict ()
18
+
19
+
20
+ def add_vertex (self , label :str ) -> None :
21
+ self .vertices .add (label )
17
22
self .prev [label ] = None
23
+ self .distances [label ] = None
18
24
19
- def add_edge (self , label1 : str , label2 : str , weight : int ):
20
- self .edges .append ([label1 , label2 , weight ])
21
25
22
- def bellman_ford (self , source : str ) :
23
- self .distance [ source ] = 0
26
+ def add_edge (self , v1 : str , v2 : str , distance : int ) -> None :
27
+ self .edges . append (( v1 , v2 , distance ))
24
28
25
- for _ in range (len (self .vertices )):
26
29
27
- for edge in self .edges :
28
- label1 : str = edge [0 ]
29
- label2 : str = edge [1 ]
30
- weight : int = edge [2 ]
30
+ def bellman_ford (self , label :str ) -> None :
31
+ self .distances [label ] = 0
31
32
32
- if self .distance [label1 ] is None :
33
- continue
34
- if self .distance [label2 ] is None :
35
- self .distance [label2 ] = self .distance [label1 ] + weight
36
- self .prev [label2 ] = label1
37
- continue
38
- if self .distance [label1 ] + weight < self .distance [label2 ]:
39
- self .distance [label2 ] = self .distance [label1 ] + weight
40
- self .prev [label2 ] = label1
33
+ for _ in range (len (self .vertices ) - 1 ):
34
+
35
+ for v1 , v2 , distance in self .edges :
36
+ if self .distances [v1 ] is None :
41
37
continue
38
+ if self .distances [v2 ] is None or self .distances [v2 ] > self .distances [v1 ] + distance :
39
+ self .distances [v2 ] = self .distances [v1 ] + distance
40
+ self .prev [v2 ] = v1
41
+
42
+ # Check for negative-weight cycles
43
+ for v1 , v2 , distance in self .edges :
44
+ if self .distances [v1 ] is not None and self .distances [v2 ] > self .distances [v1 ] + distance :
45
+ raise ValueError ("Graph contains a negative-weight cycle" )
42
46
43
- def print_distances (self , source : str ):
47
+ self ._print_paths (label )
48
+
49
+
50
+ def _print_paths (self , label :str ) -> None :
44
51
for v in self .vertices :
45
- if v != source :
46
- distance : int = self .distance [v ]
47
- print (f'Distance from { source } to { v } is { distance } ' )
52
+ if v == label :
53
+ continue
54
+ if self .distances [v ] is not None :
55
+ print (f'Path from { label } to { v } is { self ._return_path (v )} and distance is { self .distances [v ]} ' )
56
+ else :
57
+ print (f'No path from { label } to { v } ' )
58
+
59
+
60
+ def _return_path (self , label :str ) -> str :
61
+ if self .prev [label ] is None :
62
+ return label
63
+ return self ._return_path (self .prev [label ]) + ' -> ' + label
64
+
65
+
66
+
67
+ g = Graph ()
68
+ for v in ['A' , 'B' , 'C' , 'D' ]:
69
+ g .add_vertex (v )
70
+
71
+ g .add_edge ('A' , 'B' , 1 )
72
+ g .add_edge ('B' , 'C' , 3 )
73
+ g .add_edge ('A' , 'C' , 10 )
74
+ g .add_edge ('C' , 'D' , 2 )
75
+ g .add_edge ('D' , 'B' , 4 )
76
+
77
+ g .bellman_ford ('A' )
78
+
0 commit comments