public void Run() { // create random bipartite graph with V vertices and E edges; then add F random edges const int v1 = 10; const int v2 = 10; const int e = 20; const int f = 5; // create random bipartite graph with V1 vertices on left side, // V2 vertices on right side, and E edges; then add F random edges var graph = GraphGenerator.Bipartite(v1, v2, e); for (var i = 0; i < f; i++) { var v = StdRandom.Uniform(v1 + v2); var w = StdRandom.Uniform(v1 + v2); graph.AddEdge(v, w); } Console.WriteLine(graph); var b = new BipartiteX(graph); if (b.IsBipartite()) { Console.WriteLine("Graph is bipartite"); for (var v = 0; v < graph.V; v++) { Console.WriteLine($"{v}: {b.Color(v)}"); } } else { Console.WriteLine("Graph has an odd-length cycle: "); foreach (int x in b.OddCycle()) { Console.Write($"{x} "); } Console.WriteLine(); } Console.ReadLine(); }
private int[] distTo; // distTo[v] = number of edges on shortest path to v /** * Determines a maximum matching (and a minimum vertex cover) * in a bipartite graph. * * @param G the bipartite graph * @throws IllegalArgumentException if {@code G} is not bipartite */ public HopcroftKarp(Graph G) { bipartition = new BipartiteX(G); if (!bipartition.isBipartite()) { throw new IllegalArgumentException("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 Iterator<Integer>[] adj = (Iterator<Integer>[]) new Iterator[G.V()]; for (int v = 0; v < G.V(); v++) adj[v] = G.adj(v).iterator(); // 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 Stack<Integer> path = new Stack<Integer>(); path.push(s); while (!path.isEmpty()) { int v = path.peek(); // retreat, no more edges in level graph leaving v if (!adj[v].hasNext()) path.pop(); // advance else { // process edge v-w only if it is an edge in level graph int w = adj[v].next(); if (!isLevelGraphEdge(v, w)) continue; // add w to augmenting path path.push(w); // augmenting path found: update the matching if (!isMatched(w)) { // StdOut.println("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 boolean[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; } assert certifySolution(G); }