1
1
import sys
2
+ from collections import namedtuple
2
3
3
- class Eulerian_Graph :
4
+ Node_Degree = namedtuple ('Node_Degree' , ['vertex_no' , 'in_degree' , 'out_degree' ])
5
+
6
+ class Graph :
4
7
def __init__ (self , edges ):
5
8
6
9
self ._build_graph (edges )
7
-
8
- self ._is_eulerian_graph ()
9
10
10
11
def _build_graph (self , edges ):
11
12
12
13
self .nodes = []
13
14
self .adjacency_list = []
14
15
self .reversed_adjacency_list = []
15
- self .edges_counts = 0
16
- node_label_dict = dict ()
17
16
17
+ node_label_dict = dict ()
18
18
for edge in edges :
19
19
(start_vertex_label , end_vertices_labels ) = edge .split (' -> ' )
20
20
21
21
start_vertex_no = self ._get_node_no (start_vertex_label , node_label_dict )
22
22
23
23
self .adjacency_list [start_vertex_no ] = [self ._get_node_no (label , node_label_dict ) for label in end_vertices_labels .split (',' )]
24
- self .edges_counts += len (self .adjacency_list [start_vertex_no ])
25
24
26
25
for a in self .adjacency_list [start_vertex_no ]:
27
26
self .reversed_adjacency_list [a ].append (start_vertex_no )
@@ -40,7 +39,7 @@ def _get_node_no(self, label, node_label_dict):
40
39
41
40
return node_no
42
41
43
- def _is_balanced (self ):
42
+ def find_unbalanced_vertices (self ):
44
43
45
44
# 1. Compute in_degree for each vertex
46
45
in_degree = [0 for _ in range (len (self .adjacency_list ))]
@@ -49,18 +48,16 @@ def _is_balanced(self):
49
48
in_degree [v ] += 1
50
49
51
50
# 2. Compare in_degree vs. out_degree of each vertex
52
- balanced = True
53
51
u = 0
54
- self .balanced = ""
52
+ self .unbalanced_vertices = []
55
53
while u < len (self .adjacency_list ):
56
54
if in_degree [u ] != len (self .adjacency_list [u ]):
57
- balanced = False
58
- break
55
+ self .unbalanced_vertices .append (Node_Degree (u , in_degree [u ], len (self .adjacency_list [u ])))
59
56
60
57
u += 1
61
-
62
- return balanced
63
58
59
+ return self .unbalanced_vertices
60
+
64
61
def explore (self , v , adj , postOrderVisits ):
65
62
self .visited [v ] = True
66
63
for a in adj [v ]:
@@ -76,34 +73,30 @@ def dfs(self, adj, postOrderVisits):
76
73
if not self .visited [v ]:
77
74
self .explore (v , adj , postOrderVisits )
78
75
79
- def strongly_connected_components_number (self ):
76
+ def find_strongly_connected_components (self ):
80
77
81
78
postOrderVisits = []
82
79
self .dfs (self .reversed_adjacency_list , postOrderVisits )
83
80
self .visited = [ False for _ in range (len (self .nodes )) ]
84
- aSCCList = []
81
+ self . strongly_connected_components = []
85
82
for i in range (len (postOrderVisits ) - 1 , - 1 , - 1 ):
86
83
v = postOrderVisits [i ]
87
84
if not self .visited [v ]:
88
85
aSCC = []
89
86
self .explore (v , self .adjacency_list , aSCC )
90
- aSCCList .append (aSCC )
87
+ self . strongly_connected_components .append (aSCC )
91
88
92
- return aSCCList
93
-
94
- def _is_strongly_connected (self ):
95
-
96
- aSCCList = self .strongly_connected_components_number ()
97
-
98
- return len (aSCCList ) == 1
89
+ return self .strongly_connected_components
99
90
100
91
def _is_eulerian_graph (self ):
101
92
102
93
# 1. Is balanced
103
- #assert(self._is_balanced())
94
+ self .find_unbalanced_vertices ()
95
+ assert (len (self .unbalanced_vertices ) == 0 )
104
96
105
97
# 2. Is strongly connected
106
- #assert(self._is_strongly_connected())
98
+ self .find_strongly_connected_components ()
99
+ assert (len (self .strongly_connected_components ) == 1 )
107
100
108
101
return True
109
102
@@ -129,6 +122,8 @@ def form_cycle(self, start, cycle, visited_edge_indexes, unvisited_edge_node_dic
129
122
return - 1 if len (unvisited_edge_node_dict ) == 0 else next (iter (unvisited_edge_node_dict .values ()))
130
123
131
124
def eulerian_cycle (self ):
125
+
126
+ assert (self ._is_eulerian_graph ())
132
127
133
128
cycle = []
134
129
visited_edge_indexes = [- 1 for _ in range (len (self .nodes ))]
@@ -152,11 +147,11 @@ def eulerian_cycle(self):
152
147
153
148
new_start_pos_in_cycle = self .form_cycle (new_start , cycle , visited_edge_indexes , unvisited_edge_node_dict )
154
149
155
- return '->' . join ([ self . nodes [ node ] for node in cycle ])
150
+ return cycle
156
151
157
152
if __name__ == "__main__" :
158
153
edges = sys .stdin .read ().strip ().splitlines ()
159
154
160
- eulerian_graph = Eulerian_Graph (edges )
155
+ eulerian_graph = Graph (edges )
161
156
162
- print (eulerian_graph .eulerian_cycle ())
157
+ print ('->' . join ( [ eulerian_graph .nodes [ node ] for node in eulerian_graph . eulerian_cycle () ] ))
0 commit comments