44"""
55from collections import defaultdict
66import inspect
7+ import math
78
89
910class Graph (object ):
@@ -14,14 +15,14 @@ class Graph(object):
1415 def __init__ (self ):
1516 self .graph = defaultdict (list )
1617 self .count = 0
17-
18+
1819 def print_graph (self ):
1920 """
2021 Prints the contents of the graph
2122 """
2223 for i in self .graph :
2324 print (i , '->' , ' -> ' .join ([str (j ) for j in self .graph [i ]]))
24-
25+
2526 def add_edge (self , from_vertex , to_vertex ):
2627 """
2728 Adds an edge in the graph
@@ -121,7 +122,117 @@ def kruskal_code(cls):
121122 """
122123 return inspect .getsource (cls .kruskal_mst )
123124
124-
125+ class WeightedUndirectedGraph (object ):
126+ """WeightedUndirectedGraph object
127+ A graph with a numerical value (weight) on edges, which
128+ is the same for both directions in an undirected graph.
129+ """
130+
131+ def __init__ (self ):
132+ self .graph = {}
133+ self .weights = {}
134+
135+ def add_edge (self , u , v , weight ):
136+ """
137+ Adds the specified edge to this graph. If the edge already exists,
138+ this will only modify the weight (not create duplicates).
139+ :param u: from vertex
140+ :param v: to vertex
141+ :param weight: weight of the edge - type : numeric
142+ """
143+
144+ changing_weight = (u , v ) in self .weights .keys ()
145+
146+ self .weights [(u , v )] = weight
147+ self .weights [(v , u )] = weight
148+
149+ if changing_weight :
150+ return
151+
152+ if u in self .graph .keys ():
153+ self .graph [u ].append (v )
154+ else :
155+ self .graph [u ] = [v ]
156+
157+ if v in self .graph .keys ():
158+ self .graph [v ].append (u )
159+ else :
160+ self .graph [v ] = [u ]
161+
162+ def get_edge_weight (self , u , v ):
163+ """
164+ Gets the weight between u and v if such an edge
165+ exists, or None if it does not.
166+ :param u: one edge
167+ :param v: the other edge
168+ :return: numeric or None
169+ """
170+ return self .weights .get ((u , v ), None )
171+
172+ def remove_edge (self , edge , other_edge_or_none = None ):
173+ """
174+ Removes the specified edge from the grid entirely or,
175+ if specified, the connection with one other edge.
176+ Behavior is undefined if the connection does not
177+ exist.
178+ :param edge: the edge to remove
179+ :param other_edge_or_none: an edge connected to edge or none
180+ """
181+
182+ if other_edge_or_none is not None :
183+ del self .weights [(edge , other_edge_or_none )]
184+ del self .weights [(other_edge_or_none , edge )]
185+
186+ edge_list = self .graph [edge ]
187+ other_edge_list = self .graph [other_edge_or_none ]
188+
189+ if len (edge_list ) == 1 :
190+ del self .graph [edge ]
191+ else :
192+ self .graph [edge ].remove (other_edge_or_none )
193+
194+ if len (other_edge_list ) == 1 :
195+ del self .graph [other_edge_or_none ]
196+ else :
197+ self .graph [other_edge_or_none ].remove (edge )
198+ else :
199+ edge_list = self .graph [edge ]
200+ del self .graph [edge ]
201+ for other_edge in edge_list :
202+ del self .weights [(edge , other_edge )]
203+ del self .weights [(other_edge , edge )]
204+
205+ other_edge_list = self .graph [other_edge ]
206+ if len (other_edge_list ) == 1 :
207+ del self .graph [other_edge ]
208+ else :
209+ other_edge_list .remove (edge )
210+
211+
212+ def gridify (self , size , weight ):
213+ """
214+ Constructs connections from a square grid starting at (0, 0)
215+ until (size-1, size-1) with connections between adjacent and
216+ diagonal nodes. Diagonal nodes have a weight of weight*sqrt(2)
217+ :param size: the size of the square grid to construct - type : integer
218+ :param weight: the weight between orthogonal nodes. - type: numeric
219+ :return: None
220+ """
221+ rt2 = math .sqrt (2 )
222+ acceptable_offsets = [
223+ (- 1 , - 1 , rt2 ), (- 1 , 0 , 1 ), (- 1 , 1 , rt2 ),
224+ (0 , - 1 , 1 ), (0 , 1 , 1 ),
225+ (1 , - 1 , rt2 ), (1 , 0 , 1 ), (1 , 1 , rt2 )
226+ ]
227+
228+ for x in range (0 , size ):
229+ for y in range (0 , size ):
230+ for offset in acceptable_offsets :
231+ nx = x + offset [0 ]
232+ ny = y + offset [1 ]
233+ if nx >= 0 and ny >= 0 and nx < size and ny < size :
234+ self .add_edge ((x , y ), (nx , ny ), weight * offset [2 ])
235+
125236class TopologicalSort (Graph ):
126237
127238 def topological_sort (self ):
@@ -241,25 +352,28 @@ class CheckCycleUndirectedGraph(object):
241352 def __init__ (self ):
242353 self .graph = {}
243354 self .count = 0
244-
355+
245356 def print_graph (self ):
246357 """
247358 for printing the contents of the graph
248359 """
249360 for i in self .graph :
250361 print (i , '->' , ' -> ' .join ([str (j ) for j in self .graph [i ]]))
251-
362+
252363 def add_edge (self , from_vertex , to_vertex ):
253364 """
254365 for adding the edge between two vertices
255366 """
256367 # check if vertex is already present,
257- if from_vertex in self .graph .keys () and to_vertex in self . graph . keys () :
368+ if from_vertex in self .graph .keys ():
258369 self .graph [from_vertex ].append (to_vertex )
259- self .graph [to_vertex ].append (from_vertex )
260370 else :
261- # else make a new vertex
371+ # otherwise add it to the graph
262372 self .graph [from_vertex ] = [to_vertex ]
373+
374+ if to_vertex in self .graph .keys ():
375+ self .graph [to_vertex ].append (from_vertex )
376+ else :
263377 self .graph [to_vertex ] = [from_vertex ]
264378
265379 def check_cycle (self ):
0 commit comments