private int[] edgeTo; // edgeTo[v] = w if v-w is last edge on path to w /// <summary> /// Determines a maximum matching (and a minimum vertex cover) /// in a bipartite graph.</summary> /// <param name="G">the bipartite graph</param> /// <exception cref="ArgumentException">if <c>G</c> is not bipartite</exception> /// public BipartiteMatching(Graph G) { bipartition = new BipartiteX(G); if (!bipartition.IsBipartite) { throw new ArgumentException("graph is not bipartite"); } numVertices = G.V; // initialize empty matching mate = new int[numVertices]; for (int v = 0; v < numVertices; v++) { mate[v] = UNMATCHED; } // alternating path algorithm while (hasAugmentingPath(G)) { // find one endpoint t in alternating path int t = -1; for (int v = 0; v < numVertices; v++) { if (!IsMatched(v) && edgeTo[v] != -1) { t = v; break; } } // update the matching according to alternating path in edgeTo[] array for (int v = t; v != -1; v = edgeTo[edgeTo[v]]) { int w = edgeTo[v]; mate[v] = w; mate[w] = v; } cardinality++; } // find min vertex cover from marked[] array inMinVertexCover = new bool[numVertices]; for (int v = 0; v < numVertices; v++) { if (bipartition.Color(v) && !marked[v]) { inMinVertexCover[v] = true; } if (!bipartition.Color(v) && marked[v]) { inMinVertexCover[v] = true; } } Debug.Assert(certifySolution(G)); }
// is the edge v-w a forward edge not in the matching or a reverse edge in the matching? private bool isResidualGraphEdge(int v, int w) { if ((mate[v] != w) && bipartition.Color(v)) { return(true); } if ((mate[v] == w) && !bipartition.Color(v)) { return(true); } return(false); }
// is there an augmenting path? // an alternating path is a path whose edges belong alternately to the matching and not to the matching // an augmenting path is an alternating path that starts and ends at unmatched vertices // // if so, upon termination edgeTo[] contains a parent-link representation of such a path // if not, upon terminatation marked[] specifies the subset of vertices reachable via an alternating // path from one side of the bipartition // // this implementation finds a shortest augmenting path (fewest number of edges), though there // is no particular advantage to do so here private bool hasAugmentingPath(Graph G) { marked = new bool[numVertices]; edgeTo = new int[numVertices]; for (int v = 0; v < numVertices; v++) { edgeTo[v] = -1; } // breadth-first search (starting from all unmatched vertices on one side of bipartition) LinkedQueue <int> queue = new LinkedQueue <int>(); for (int v = 0; v < numVertices; v++) { if (bipartition.Color(v) && !IsMatched(v)) { queue.Enqueue(v); marked[v] = true; } } // run BFS, stopping as soon as an alternating path is found while (!queue.IsEmpty) { int v = queue.Dequeue(); foreach (int w in G.Adj(v)) { // either (1) forward edge not in matching or (2) backward edge in matching if (isResidualGraphEdge(v, w)) { if (!marked[w]) { edgeTo[w] = v; marked[w] = true; if (!IsMatched(w)) { return(true); } queue.Enqueue(w); } } } } return(false); }
private static void BipartiteXReport(BipartiteX b) { if (b.IsBipartite) { Graph G = b.G; Console.WriteLine("Graph is bipartite"); for (int v = 0; v < G.V; v++) { Console.WriteLine(v + ": " + b.Color(v)); } } else { Console.Write("Graph has an odd-length cycle: "); foreach (int x in b.OddCycle()) { Console.Write(x + " "); } } Console.WriteLine(); }
private int[] distTo; // distTo[v] = number of edges on shortest path to v /// <summary> /// Determines a maximum matching (and a minimum vertex cover) /// in a bipartite graph.</summary> /// <param name="G">the bipartite graph</param> /// <exception cref="ArgumentException">if <c>G</c> is not bipartite</exception> /// public HopcroftKarp(Graph G) { bipartition = new BipartiteX(G); if (!bipartition.IsBipartite) { throw new ArgumentException("graph is not bipartite"); } // initialize empty matching this.V = G.V; mate = new int[V]; for (int v = 0; v < V; v++) { mate[v] = UNMATCHED; } // the call to hasAugmentingPath() provides enough info to reconstruct level graph while (hasAugmentingPath(G)) { // to be able to iterate over each adjacency list, keeping track of which // vertex in each adjacency list needs to be explored next IEnumerator <int>[] adj = new IEnumerator <int> [G.V]; for (int v = 0; v < G.V; v++) { adj[v] = G.Adj(v).GetEnumerator(); } // for each unmatched vertex s on one side of bipartition for (int s = 0; s < V; s++) { if (IsMatched(s) || !bipartition.Color(s)) { continue; // or use distTo[s] == 0 } // find augmenting path from s using nonrecursive DFS LinkedStack <int> path = new LinkedStack <int>(); path.Push(s); while (!path.IsEmpty) { int v = path.Peek(); // retreat, no more edges in level graph leaving v if (!adj[v].MoveNext()) { path.Pop(); } // advance else { // process edge v-w only if it is an edge in level graph int w = adj[v].Current; if (!isLevelGraphEdge(v, w)) { continue; } // add w to augmenting path path.Push(w); // augmenting path found: update the matching if (!IsMatched(w)) { // Console.WriteLine("augmenting path: " + toString(path)); while (!path.IsEmpty) { int x = path.Pop(); int y = path.Pop(); mate[x] = y; mate[y] = x; } cardinality++; } } } } } // also find a min vertex cover inMinVertexCover = new bool[V]; for (int v = 0; v < V; v++) { if (bipartition.Color(v) && !marked[v]) { inMinVertexCover[v] = true; } if (!bipartition.Color(v) && marked[v]) { inMinVertexCover[v] = true; } } Debug.Assert(certifySolution(G)); }