/// <summary> /// We can get the min cut using the max-flow min-cut theorm, which states that the max flow in a n/w = min-cut of the network. /// Steps: /// 1. Run FordFulkerson algo to get the residual graph. /// 2. Find the set of vertices that can be reached from the source vertex. /// 3. Get all the edges from vertices in this set to the vertices which are not present in this set. /// this will give all the edges of the min cut. /// /// The running time of this algo is same as the ford fulkerson's max flow algo with edward karp optimization /// O(V(E^2)) /// </summary> /// <param name="graph">graph object</param> /// <param name="startId">id of the source vertex</param> /// <param name="endId">id of the sink vertex</param> /// <returns></returns> public List <string> GetMinCut(GraphWithFwdEdges graph, string startId, string endId) { List <string> setOfEdges = new List <string>(); // 1. Run FordFulkerson algo to get the residual graph. FordFulkersonEdmondKarp ffkp = new FordFulkersonEdmondKarp(); ffkp.GetTheMaxFlow(graph, startId, endId); // 2. Find the set of vertices that can be reached from the source vertex. Dictionary <GraphVertex, bool> setOfVerticesFromSource = GetAllVerticesThatCanBeReachedFromSrc(graph, startId); // 3.Get all the forward edges from vertices in this set to the vertices which are not present in this set. foreach (GraphVertex vertex in setOfVerticesFromSource.Keys) { foreach (GraphVertex neighbour in vertex.Neighbours) { string edgeId = vertex.Id + "#" + neighbour.Id; if (graph.IsEdgeFwd[edgeId] && !setOfVerticesFromSource.ContainsKey(neighbour)) { // the graph edge should not have 0 flow and also should not be present in the current set(found after the cut) setOfEdges.Add(edgeId); } } } return(setOfEdges); }
/// <summary> /// Create a source vertex which has edge with unit weight to all the employees. /// Note we are using unit edge weight cause each employee can take up only one job. /// Also create a sink vertex, all the jobs will have a directed edge towards the sink and the edge weight is 1. /// The unit edge weight is used cause each job must be done by one employee. /// </summary> /// <param name="employeeJobPreference">dictionary having key as the employeeid and value as the list of job ids which are prefered</param> public MaximumBipartiteMatching(Dictionary <string, List <string> > employeeJobPreference) { // initialize the graph Graph = new GraphWithFwdEdges(); foreach (string employeeId in employeeJobPreference.Keys) { Graph.AddEdge(StartId, employeeId, 1); // Add fwd edge Graph.AddEdge(employeeId, StartId, 0, false); // Add backedge foreach (string jobId in employeeJobPreference[employeeId]) { Graph.AddEdge(employeeId, jobId, 1); // Add fwdEdge Graph.AddEdge(jobId, employeeId, 0, false); // Add back edge // Add the directed edge towards sink from the job id Graph.AddEdge(jobId, SinkId, 1); // Add fwdEdge Graph.AddEdge(SinkId, jobId, 0, false); // Add back edge } } }
public static void TestMinCut() { MinCut mc = new MinCut(); /* * (A)<------3--------(B) | X /x | \ / | | 3 4 | | \ / | | 3 \ x | | (C) 1 | / \ | | / \ | | 1 2 | | x x | | (D)-------2------>(E) | | | | | | | 6 1 | | | x X | (F)-------9------->(G) */ GraphWithFwdEdges graph = new GraphWithFwdEdges(); graph.AddEdge("A", "B", 3); graph.AddEdge("B", "A", 0, false); graph.AddEdge("A", "D", 3); graph.AddEdge("D", "A", 0, false); graph.AddEdge("D", "E", 2); graph.AddEdge("E", "D", 0, false); graph.AddEdge("E", "B", 1); graph.AddEdge("B", "E", 0, false); graph.AddEdge("C", "A", 3); graph.AddEdge("A", "C", 0, false); graph.AddEdge("B", "C", 4); graph.AddEdge("C", "B", 0, false); graph.AddEdge("C", "D", 1); graph.AddEdge("D", "C", 0, false); graph.AddEdge("C", "E", 2); graph.AddEdge("E", "C", 0, false); graph.AddEdge("D", "F", 6); graph.AddEdge("F", "D", 0, false); graph.AddEdge("F", "G", 9); graph.AddEdge("G", "F", 0, false); graph.AddEdge("E", "G", 1); graph.AddEdge("G", "E", 0, false); List <string> setOfEdges = mc.GetMinCut(graph, "A", "G"); PrintEdges(setOfEdges); graph = new GraphWithFwdEdges(); graph.AddEdge("0", "1", 16); graph.AddEdge("1", "2", 10); graph.AddEdge("0", "2", 13); graph.AddEdge("2", "1", 4); graph.AddEdge("1", "3", 12); graph.AddEdge("3", "2", 9); graph.AddEdge("2", "4", 14); graph.AddEdge("4", "3", 7); graph.AddEdge("4", "5", 4); graph.AddEdge("3", "5", 20); graph.AddEdge("1", "0", 0, false); graph.AddEdge("2", "0", 0, false); graph.AddEdge("3", "1", 0, false); graph.AddEdge("2", "3", 0, false); graph.AddEdge("4", "2", 0, false); graph.AddEdge("3", "4", 0, false); graph.AddEdge("5", "4", 0, false); graph.AddEdge("5", "3", 0, false); setOfEdges = mc.GetMinCut(graph, "0", "5"); PrintEdges(setOfEdges); }