2
2
3
3
UNMATCHED = - 1 # Constant to represent unmatched vertices
4
4
5
- class EdmondsBlossomAlgorithm :
6
5
6
+ class EdmondsBlossomAlgorithm :
7
7
@staticmethod
8
8
def maximum_matching (edges , vertex_count ):
9
9
"""
@@ -22,25 +22,37 @@ def maximum_matching(edges, vertex_count):
22
22
graph [v ].append (u )
23
23
24
24
# Initialize matching array and other auxiliary structures
25
- match = [UNMATCHED ] * vertex_count # Stores matches for each vertex, initially unmatched
26
- parent = [UNMATCHED ] * vertex_count # Tracks the parent of each vertex in the augmenting path
27
- base = list (range (vertex_count )) # Base of each vertex (initially the vertex itself)
25
+ match = [
26
+ UNMATCHED
27
+ ] * vertex_count # Stores matches for each vertex, initially unmatched
28
+ parent = [
29
+ UNMATCHED
30
+ ] * vertex_count # Tracks the parent of each vertex in the augmenting path
31
+ base = list (
32
+ range (vertex_count )
33
+ ) # Base of each vertex (initially the vertex itself)
28
34
in_blossom = [False ] * vertex_count # Marks if a vertex is part of a blossom
29
- in_queue = [False ] * vertex_count # Marks if a vertex is already in the BFS queue
35
+ in_queue = [
36
+ False
37
+ ] * vertex_count # Marks if a vertex is already in the BFS queue
30
38
31
39
# Iterate over each vertex to start the matching process
32
40
for u in range (vertex_count ):
33
41
if match [u ] == UNMATCHED : # Proceed only if the vertex is unmatched
34
42
# Reset auxiliary data structures for BFS
35
43
parent = [UNMATCHED ] * vertex_count
36
- base = list (range (vertex_count )) # Each vertex is its own base initially
44
+ base = list (
45
+ range (vertex_count )
46
+ ) # Each vertex is its own base initially
37
47
in_blossom = [False ] * vertex_count
38
48
in_queue = [False ] * vertex_count
39
49
40
50
queue = deque ([u ]) # Initialize BFS queue
41
51
in_queue [u ] = True # Mark u as in the queue
42
52
43
- augmenting_path_found = False # Flag to track if an augmenting path is found
53
+ augmenting_path_found = (
54
+ False # Flag to track if an augmenting path is found
55
+ )
44
56
45
57
# BFS to find augmenting paths
46
58
while queue and not augmenting_path_found :
@@ -60,7 +72,9 @@ def maximum_matching(edges, vertex_count):
60
72
if match [y ] == UNMATCHED :
61
73
parent [y ] = current
62
74
augmenting_path_found = True
63
- EdmondsBlossomAlgorithm .update_matching (match , parent , y ) # Augment the path
75
+ EdmondsBlossomAlgorithm .update_matching (
76
+ match , parent , y
77
+ ) # Augment the path
64
78
break
65
79
66
80
# Case 2: y is matched, add y's match to the queue
@@ -72,10 +86,16 @@ def maximum_matching(edges, vertex_count):
72
86
in_queue [z ] = True
73
87
else :
74
88
# Case 3: A cycle (blossom) is detected
75
- base_u = EdmondsBlossomAlgorithm .find_base (base , parent , current , y )
89
+ base_u = EdmondsBlossomAlgorithm .find_base (
90
+ base , parent , current , y
91
+ )
76
92
if base_u != UNMATCHED :
77
- aux_data = BlossomAuxData (queue , parent , base , in_blossom , match , in_queue )
78
- EdmondsBlossomAlgorithm .contract_blossom (BlossomData (aux_data , current , y , base_u ))
93
+ aux_data = BlossomAuxData (
94
+ queue , parent , base , in_blossom , match , in_queue
95
+ )
96
+ EdmondsBlossomAlgorithm .contract_blossom (
97
+ BlossomData (aux_data , current , y , base_u )
98
+ )
79
99
80
100
# Collect the final matching result
81
101
matching_result = []
@@ -139,13 +159,21 @@ def contract_blossom(blossom_data):
139
159
:param blossom_data: An object containing the necessary data to perform the contraction.
140
160
"""
141
161
# Mark all vertices in the blossom
142
- for x in range (blossom_data .u , blossom_data .aux_data .base [blossom_data .u ] != blossom_data .lca , blossom_data .aux_data .parent [blossom_data .aux_data .match [x ]]):
162
+ for x in range (
163
+ blossom_data .u ,
164
+ blossom_data .aux_data .base [blossom_data .u ] != blossom_data .lca ,
165
+ blossom_data .aux_data .parent [blossom_data .aux_data .match [x ]],
166
+ ):
143
167
base_x = blossom_data .aux_data .base [x ]
144
168
match_base_x = blossom_data .aux_data .base [blossom_data .aux_data .match [x ]]
145
169
blossom_data .aux_data .in_blossom [base_x ] = True
146
170
blossom_data .aux_data .in_blossom [match_base_x ] = True
147
171
148
- for x in range (blossom_data .v , blossom_data .aux_data .base [blossom_data .v ] != blossom_data .lca , blossom_data .aux_data .parent [blossom_data .aux_data .match [x ]]):
172
+ for x in range (
173
+ blossom_data .v ,
174
+ blossom_data .aux_data .base [blossom_data .v ] != blossom_data .lca ,
175
+ blossom_data .aux_data .parent [blossom_data .aux_data .match [x ]],
176
+ ):
149
177
base_x = blossom_data .aux_data .base [x ]
150
178
match_base_x = blossom_data .aux_data .base [blossom_data .aux_data .match [x ]]
151
179
blossom_data .aux_data .in_blossom [base_x ] = True
@@ -164,6 +192,7 @@ class BlossomAuxData:
164
192
"""
165
193
A helper class to encapsulate auxiliary data used during blossom contraction.
166
194
"""
195
+
167
196
def __init__ (self , queue , parent , base , in_blossom , match , in_queue ):
168
197
self .queue = queue # The BFS queue used for traversal
169
198
self .parent = parent # The parent array for each vertex
@@ -177,6 +206,7 @@ class BlossomData:
177
206
"""
178
207
A helper class to store parameters necessary for blossom contraction.
179
208
"""
209
+
180
210
def __init__ (self , aux_data , u , v , lca ):
181
211
self .aux_data = aux_data # The auxiliary data object
182
212
self .u = u # One vertex in the current edge
0 commit comments