1
+ #include " ../Headers/0003_Graph/0017_MaximumBipartiteMatching.h"
2
+ #include < climits>
3
+ #include < queue>
4
+ using namespace std ;
5
+
6
+ namespace MaximumBipartiteMatching
7
+ {
8
+ // Graph Private Member Methods
9
+ void Graph::ResolveAntiParallelEdges ()
10
+ {
11
+ int countParallelEdges = 0 ;
12
+ for (int i = 0 ; i < this ->_noOfVertices ; i++)
13
+ {
14
+ for (int j = 0 ; j < this ->_noOfVertices ; j++)
15
+ {
16
+ if (this ->_adjMatrix [i][j] > 0 && this ->_adjMatrix [j][i] > 0 )
17
+ {
18
+ countParallelEdges++;
19
+ }
20
+ }
21
+ }
22
+
23
+ // As i->j and j->i both edges has been counted, actual count is count = count / 2
24
+ countParallelEdges /= 2 ;
25
+
26
+ this ->_flagParallelEdges = countParallelEdges > 0 ;
27
+
28
+ // If there are no anti-parallel edges, no need to modify the adjMatrix
29
+ if (!this ->_flagParallelEdges )
30
+ {
31
+ return ;
32
+ }
33
+
34
+ int newNoOfVertices = this ->_noOfVertices + countParallelEdges;
35
+
36
+ // Modifying the adjMatrix
37
+ for (auto & edge : this ->_adjMatrix )
38
+ {
39
+ edge.resize (newNoOfVertices, 0 );
40
+ }
41
+ int k = this ->_noOfVertices ;
42
+ this ->_visited .resize (newNoOfVertices, false );
43
+ this ->_parent .resize (newNoOfVertices, -1 );
44
+ this ->_adjMatrix .resize (newNoOfVertices, vector<int >(newNoOfVertices, 0 ));
45
+
46
+ // Removing the anti-parallel edges by adding new nodes
47
+ for (int i = 0 ; i < this ->_noOfVertices ; i++)
48
+ {
49
+ for (int j = 0 ; j < this ->_noOfVertices ; j++)
50
+ {
51
+ if (this ->_adjMatrix [i][j] > 0 && this ->_adjMatrix [j][i] > 0 )
52
+ {
53
+ this ->_adjMatrix [i][k] = this ->_adjMatrix [i][j];
54
+ this ->_adjMatrix [k][j] = this ->_adjMatrix [i][j];
55
+ this ->_adjMatrix [i][j] = 0 ;
56
+ k++;
57
+ }
58
+ }
59
+ }
60
+
61
+ // Updating the total no of vertices after modifying the adjMatrix
62
+ this ->_noOfVertices = newNoOfVertices;
63
+ }
64
+
65
+ // This method is used to color the vertices of the graph to determine if the given graph is bipartite or not
66
+ void Graph::ColorGraph ()
67
+ {
68
+ // Color of all the vertices are initialised to WHITE
69
+ fill (this ->_color .begin (), this ->_color .end (), WHITE);
70
+
71
+ // Queue to hold the vertices
72
+ queue<int > nodeQueue;
73
+
74
+ for (int node = 0 ; node < this ->_noOfVertices ; node++)
75
+ {
76
+ // Check if the node is already not colored
77
+ if (this ->_color [node] == WHITE)
78
+ {
79
+ // The color of the node is set to RED
80
+ this ->_color [node] = RED;
81
+
82
+ // The node is inserted into the queue
83
+ nodeQueue.push (node);
84
+
85
+ // Using BFS method to color all the vertices
86
+ while (!nodeQueue.empty ())
87
+ {
88
+ int nodeU = nodeQueue.front ();
89
+ nodeQueue.pop ();
90
+
91
+ // Iterating over G.Adj[nodeU]
92
+ for (int nodeV = 0 ; nodeV < this ->_noOfVertices ; nodeV++)
93
+ {
94
+ // As there are no self loops, continue
95
+ if (nodeU == nodeV)
96
+ {
97
+ continue ;
98
+ }
99
+ // Check if there is an edge u --> v and nodeV is not colored yet
100
+ else if (this ->_residualGraph [nodeU][nodeV] != 0 && this ->_color [nodeV] == WHITE)
101
+ {
102
+ // Set the color of nodeV opposite of nodeU
103
+ this ->_color [nodeV] = 1 - this ->_color [nodeU];
104
+ // Insert the nodeV into the queue
105
+ nodeQueue.push (nodeV);
106
+ }
107
+ // Check if there is an edge u --> v and nodeV is of same color as nodeU
108
+ else if (this ->_residualGraph [nodeU][nodeV] != 0 && this ->_color [nodeV] == this ->_color [nodeU])
109
+ {
110
+ // Set the _isBipartite flag to false and return
111
+ this ->_isBipartite = false ;
112
+ return ;
113
+ }
114
+ }
115
+ }
116
+ }
117
+ }
118
+
119
+ // If the above operation completes without returning yet that indicates the graph is bipartite
120
+ // Set the _isBipartite flag to true and return
121
+ this ->_isBipartite = true ;
122
+ return ;
123
+ }
124
+
125
+ // This method is used to create the additional edges
126
+ // from the source vertex to the RED colored vertices and
127
+ // from the BLUE colored vertices to the sink vertex
128
+ void Graph::AddAdditionalEdges ()
129
+ {
130
+ // Resizing the residual graph to accomodate space for the new edges
131
+ for (auto & edge : this ->_residualGraph )
132
+ {
133
+ edge.resize (this ->_noOfVertices , 0 );
134
+ }
135
+
136
+ this ->_parent .resize (this ->_noOfVertices , -1 );
137
+ this ->_visited .resize (this ->_noOfVertices , false );
138
+ this ->_color .resize (this ->_noOfVertices , WHITE);
139
+ this ->_residualGraph .resize (this ->_noOfVertices , vector<int >(this ->_noOfVertices , 0 ));
140
+
141
+ // Creating the additional edges
142
+ for (int node = 0 ; node < this ->_source ; node++)
143
+ {
144
+ // From source vertex --> RED colored vertices
145
+ if (this ->_color [node] == RED)
146
+ {
147
+ this ->_residualGraph [this ->_source ][node] = 1 ;
148
+ }
149
+
150
+ // From BLUE colored vertices --> sink vertex
151
+ else if (this ->_color [node] == BLUE)
152
+ {
153
+ this ->_residualGraph [node][this ->_sink ] = 1 ;
154
+ }
155
+ }
156
+ }
157
+
158
+ // Implementation of BreadthFirstSearch for EdmondsKarp algorithm to find the path from source to sink
159
+ bool Graph::BreadthFirstSearch ()
160
+ {
161
+ // Resetting the visited values
162
+ fill (this ->_visited .begin (), this ->_visited .end (), false );
163
+
164
+ // Resetting the parent values
165
+ fill (this ->_parent .begin (), this ->_parent .end (), -1 );
166
+
167
+ queue<int > nodeQueue;
168
+ nodeQueue.push (this ->_source );
169
+ this ->_visited [this ->_source ] = true ;
170
+
171
+ while (!nodeQueue.empty ())
172
+ {
173
+ int nodeU = nodeQueue.front ();
174
+ nodeQueue.pop ();
175
+
176
+ for (int nodeV = 0 ; nodeV < this ->_noOfVertices ; nodeV++)
177
+ {
178
+ if (!this ->_visited [nodeV] && this ->_residualGraph [nodeU][nodeV] > 0 )
179
+ {
180
+ this ->_parent [nodeV] = nodeU;
181
+ this ->_visited [nodeV] = true ;
182
+ nodeQueue.push (nodeV);
183
+ }
184
+ }
185
+ }
186
+
187
+ // Returning the visited value of the sink vertex, initially it was set to false
188
+ return this ->_visited [this ->_sink ];
189
+ }
190
+
191
+ // Graph Public Member Methods
192
+ void Graph::CreateGraph (int noOfVertices)
193
+ {
194
+ this ->_noOfVertices = noOfVertices;
195
+ this ->_maximumFlow = 0 ;
196
+ this ->_flagParallelEdges = false ;
197
+ this ->_adjMatrix = vector<vector<int >>(this ->_noOfVertices , vector<int >(this ->_noOfVertices , 0 ));
198
+ this ->_parent = vector<int >(this ->_noOfVertices , -1 );
199
+ this ->_visited = vector<bool >(this ->_noOfVertices , false );
200
+ this ->_color = vector<int >(this ->_noOfVertices , WHITE);
201
+ }
202
+
203
+ void Graph::PushDirectedEdge (int valueU, int valueV)
204
+ {
205
+ this ->_adjMatrix [valueU][valueV] = 1 ;
206
+ }
207
+
208
+ int Graph::FindMaximumBipartiteMatching ()
209
+ {
210
+ // Resolving all the parallel edges if present
211
+ this ->ResolveAntiParallelEdges ();
212
+ this ->_residualGraph = this ->_adjMatrix ;
213
+
214
+ this ->ColorGraph ();
215
+
216
+ this ->_source = this ->_noOfVertices ;
217
+ this ->_noOfVertices ++;
218
+ this ->_sink = this ->_noOfVertices ;
219
+ this ->_noOfVertices ++;
220
+
221
+ this ->AddAdditionalEdges ();
222
+
223
+ // While there exists a path p from source to sink in the residual network G'
224
+ while (this ->BreadthFirstSearch ())
225
+ {
226
+ int augmentedPathFlow = 1 ;
227
+
228
+ // No need to find the minimum amount of augmentedPathFlow as like standard EdmondsKarp algorithm
229
+ // as here capacity of each edges is 1
230
+ for (int nodeV = this ->_sink ; nodeV != this ->_source ; nodeV = this ->_parent [nodeV])
231
+ {
232
+ int nodeU = this ->_parent [nodeV];
233
+ this ->_residualGraph [nodeU][nodeV] -= augmentedPathFlow;
234
+ this ->_residualGraph [nodeV][nodeU] += augmentedPathFlow;
235
+ }
236
+ this ->_maximumFlow += augmentedPathFlow;
237
+ }
238
+
239
+ return this ->_maximumFlow ;
240
+ }
241
+
242
+ // This method is used for finding the matchings
243
+ vector<vector<int >> Graph::GetMatchings ()
244
+ {
245
+ for (int nodeU = 0 ; nodeU < this ->_adjMatrix .size (); nodeU++)
246
+ {
247
+ for (int nodeV = 0 ; nodeV < this ->_adjMatrix .size (); nodeV++)
248
+ {
249
+ // Check if the nodeU and nodeV are not source or sink
250
+ // and there is a flow of 1 unit from nodeU --> nodeV
251
+ // which means nodeU --> nodeV is being used for the maximum flow (maximum matching)
252
+ if ((nodeU != this ->_source || nodeU != this ->_sink || nodeV != this ->_source || nodeV != this ->_sink )
253
+ &&
254
+ (this ->_adjMatrix [nodeU][nodeV] - this ->_residualGraph [nodeU][nodeV]) == 1 )
255
+ {
256
+ this ->_matchings .push_back ({ nodeU, nodeV });
257
+ }
258
+ }
259
+ }
260
+
261
+ return this ->_matchings ;
262
+ }
263
+ }
0 commit comments