static int[] FindMatching(bool[][] bipartiteGraph) { int numLeft = bipartiteGraph.Length; int numRight = bipartiteGraph[0].Length; int[] matching = new int[numLeft]; FlowGraph graph = ReadGraph(bipartiteGraph); MaxFlow(graph, 0, graph.Size() - 1); for (int i = 0; i < numLeft; i++) { foreach (int id in graph.GetIds(i + 1)) { Edge edge = graph.GetEdge(id); if (edge.flow == 1) { matching[i] = edge.to - numLeft; break; } matching[i] = -1; } } return(matching); }
static void MaxFlow(FlowGraph graph, int from, int to) { while (true) { bool foundPath = false; var queue = new Queue <int>(); var parentIds = new int[graph.Size()]; for (int i = 0; i < parentIds.Length; i++) { parentIds[i] = -1; //unvisited nodes are -1 } queue.Enqueue(0); //Breadth-first search, finding shortest path while (queue.Count != 0 && !foundPath) { int node = queue.Dequeue(); var ids = graph.GetIds(node); // all the edges from current node foreach (int id in ids) { var edge = graph.GetEdge(id); if (edge.flow < edge.capacity && parentIds[edge.to] == -1) // if there's capacity left and "edge pointing" vertice isn't visited { if (edge.to == edge.from) { continue; } parentIds[edge.to] = id; if (edge.to == graph.Size() - 1) // we found path { foundPath = true; break; } queue.Enqueue(edge.to); } } } if (!foundPath) { break; } //find the value of the flow to = graph.Size() - 1; var minCap = -1; //calculate min capacity while (to != 0) { var id = parentIds[to]; var edge = graph.GetEdge(id); if (minCap == -1 || (edge.capacity - edge.flow) < minCap) { minCap = edge.capacity - edge.flow; } to = edge.from; } to = graph.Size() - 1; //adding flow to edges while (to != 0) { var id = parentIds[to]; var edge = graph.GetEdge(id); graph.AddFlow(id, minCap); to = edge.from; } } }
static int MaxFlow(FlowGraph graph, int from, int to) { int flow = 0; while (true) { bool foundPath = false; var queue = new Queue <int>(); var parentIds = new int[graph.Size()]; for (int i = 0; i < parentIds.Length; i++) { parentIds[i] = -1; //unvisited nodes are -1 } queue.Enqueue(0); //bfs while (queue.Count != 0 && !foundPath) { int node = queue.Dequeue(); var ids = graph.GetIds(node); // all the edges from current node foreach (int id in ids) { var edge = graph.GetEdge(id); if (edge.flow < edge.capacity && parentIds[edge.to] == -1) { if (edge.to == edge.from) { continue; } parentIds[edge.to] = id; if (edge.to == graph.Size() - 1) // we found path { foundPath = true; break; } queue.Enqueue(edge.to); } } } if (!foundPath) { break; } //find the value of the flow to = graph.Size() - 1; var minCap = -1; //calculate min capacity while (to != 0) { var id = parentIds[to]; var edge = graph.GetEdge(id); if (minCap == -1 || (edge.capacity - edge.flow) < minCap) { minCap = edge.capacity - edge.flow; } to = edge.from; } to = graph.Size() - 1; //adding flow to edges while (to != 0) { var id = parentIds[to]; var edge = graph.GetEdge(id); graph.AddFlow(id, minCap); to = edge.from; } } //calculate the flow // to do that we only sum the flows of the start node foreach (int id in graph.GetIds(0)) { var edge = graph.GetEdge(id); flow += edge.flow; } return(flow); }