// is there an augmenting path? // if so, upon termination edgeTo[] will contain a parent-link representation of such a path // this implementation finds a shortest augmenting path (fewest number of edges), // which performs well both in theory and in practice private bool hasAugmentingPath(FlowNetwork G, int s, int t) { edgeTo = new FlowEdge[G.V]; marked = new bool[G.V]; // breadth-first search LinkedQueue <int> queue = new LinkedQueue <int>(); queue.Enqueue(s); marked[s] = true; while (!queue.IsEmpty && !marked[t]) { int v = queue.Dequeue(); foreach (FlowEdge e in G.Adj(v)) { int w = e.Other(v); // if residual capacity from v to w if (e.ResidualCapacityTo(w) > 0) { if (!marked[w]) { edgeTo[w] = e; marked[w] = true; queue.Enqueue(w); } } } } // is there an augmenting path? return(marked[t]); }
// return excess flow at vertex v private double excess(FlowNetwork G, int v) { double excess = 0.0; foreach (FlowEdge e in G.Adj(v)) { if (v == e.From) { excess -= e.Flow; } else { excess += e.Flow; } } return(excess); }
// check optimality conditions private bool check(FlowNetwork G, int s, int t) { // check that flow is feasible if (!isFeasible(G, s, t)) { Console.Error.WriteLine("Flow is infeasible"); return(false); } // check that s is on the source side of min cut and that t is not on source side if (!InCut(s)) { Console.Error.WriteLine("source " + s + " is not on source side of min cut"); return(false); } if (InCut(t)) { Console.Error.WriteLine("sink " + t + " is on source side of min cut"); return(false); } // check that value of min cut = value of max flow double mincutValue = 0.0; for (int v = 0; v < G.V; v++) { foreach (FlowEdge e in G.Adj(v)) { if ((v == e.From) && InCut(e.From) && !InCut(e.To)) { mincutValue += e.Capacity; } } } if (Math.Abs(mincutValue - value) > FloatingPointEpsilon) { Console.Error.WriteLine("Max flow value = " + value + ", min cut value = " + mincutValue); return(false); } return(true); }
// return excess flow at vertex v private bool isFeasible(FlowNetwork G, int s, int t) { // check that capacity constraints are satisfied for (int v = 0; v < G.V; v++) { foreach (FlowEdge e in G.Adj(v)) { if (e.Flow < -FloatingPointEpsilon || e.Flow > e.Capacity + FloatingPointEpsilon) { Console.Error.WriteLine("Edge does not satisfy capacity constraints: " + e); return(false); } } } // check that net flow into a vertex equals zero, except at source and sink if (Math.Abs(value + excess(G, s)) > FloatingPointEpsilon) { Console.Error.WriteLine("Excess at source = " + excess(G, s)); Console.Error.WriteLine("Max flow = " + value); return(false); } if (Math.Abs(value - excess(G, t)) > FloatingPointEpsilon) { Console.Error.WriteLine("Excess at sink = " + excess(G, t)); Console.Error.WriteLine("Max flow = " + value); return(false); } for (int v = 0; v < G.V; v++) { if (v == s || v == t) { continue; } else if (Math.Abs(excess(G, v)) > FloatingPointEpsilon) { Console.Error.WriteLine("Net flow out of " + v + " doesn't equal zero"); return(false); } } return(true); }
public static void MainTest(string[] args) { //create flow network with V vertices and E edges int V = int.Parse(args[0]); int E = int.Parse(args[1]); int s = 0, t = V - 1; FlowNetwork G = new FlowNetwork(V, E); Console.WriteLine(G); // compute maximum flow and minimum cut FordFulkerson maxflow = new FordFulkerson(G, s, t); Console.WriteLine("Max flow from " + s + " to " + t); for (int v = 0; v < G.V; v++) { foreach (FlowEdge e in G.Adj(v)) { if ((v == e.From) && e.Flow > 0) { Console.WriteLine(" " + e); } } } // print min-cut Console.Write("Min cut: "); for (int v = 0; v < G.V; v++) { if (maxflow.InCut(v)) { Console.Write(v + " "); } } Console.WriteLine(); Console.WriteLine("Max flow value = " + maxflow.Value); }