CS302 Lecture Notes - Network Flow

Maximum Flows, Minimum Cuts, Residual Graphs, The Edmonds-Karp Algorithm


The Basics of Network Flow

The best description that I have found of the basics of network flow come from a topcoder tutorial, which is available here. Read it thoroughly -- both pages. Pay special attention to the relationship between network flow and matching in a bipartite graph, as you will need it for your lab.

There is more material in the following Wikipedia pages. As with a lot of Wikipedia, the presentation is too dry and mathematical, so I don't require that you read it, but I provide links to it anyway:


A pathological example of why you need a smart path-finding algorithm

This is a classic example of why you need to have a smart algorithm for finding each augmenting path. Behold the following graph:

It's pretty easy to eyeball this graph and see that it has a maximum flow of 1000. The two paths are S->A->T and S->B->T. However, if you try to determine the maximum flow using augmenting paths, and you choose the wrong path at each step, it will take 1000 iterations of the algorithm. To illustrate, suppose that the first path you choose is S->A->B->T with a flow of one. When you process this path through the residual graph, you end up with the following:

At the next iteration, suppose you choose the path S->B->A->T, again with a flow of one. The residual looks as follows:

You continue in that vein. The pictures below show how you choose S->A->B->T again, and then S->B->A->T, again:

Each time, you add one unit of flow, which means that this will take 1000 iterations. Although this example is unlikely to happen in practice, it demonstrates a need for a smart determination of paths. Below, we will present three determinations. In the third set of lecture notes, we will evaluate these experimentally on a set of graphs.


Greedy Depth-First Search

The pathelogical example highlights a problem -- choosing paths with little flow. One way to combat this problem is to perform your DFS so that you prefer edges with a lot of flow to edges with a little flow. You can implement that by having your adjacency lists be sorted by flow, and then running a standard DFS on them. I'll show the augmenting paths that arise with this method on the example graph below. The source is A and the sink is G:

When we perform a greedy DFS on this graph, we start with edge from A to B since its flow is greater than the edge from A to D. There is only one edge leaving B. When we read node C, we traverse the edge to E, since it has the maximum flow of C's three edges. Finally, E goes to G. Thus, the first path we get is A->B->C->E->G with a flow of one.

Below, I show the flow and residual graphs when this path is processed. In the residual, the edges whose flow is reduced are colored red, and the reverse edges are colored green:

Flow

Residual

The next greedy path through the residual is A->B->C->D->F->G, with a flow of two:

Flow

Residual

The last path is A->D->F->G with a flow of three. Here are the final flow and residual graphs:

Flow

Residual


Finding the Maximum Flow Path through the Graph

Instead of using a depth-first search, you can use a modification of Dijkstra's algorithm to find the path through the residual that has the maximum flow. When processing a node, Dijkstra's algorithm traverses the node's edges, and if shorter paths to any other nodes is discovered, the nodes are updated. At each step, the node with the shortest known path is processed next.

The modification works as follows. When processing a node, again the algorithm traverses the node's edges, and if paths with more flow to any other nodes are discovered, then the nodes are updated. At each step, the node with the maximum flow is processed next.

We'll work an example with the same graph as above:

The maximum flow path here is A->D->F->G with a flow of three:

Flow

Residual

The next maximum flow path is A->B->C->D->F->G with a flow of 2:

Flow

Residual

The final path is A->B->C->E->G with a flow of one:

Flow

Residual


Edmonds-Karp: Finding the minimum hop path

Finally, the Edmonds-Karp algorithm uses a straightforward breadth-first search to find the minimum hop path through the residual graph. This is equivalent to treating the residual as an unweighted and performing a shortest path search on it.

Again, we use the same graph as an example:

There are two minimum hop paths: A->D->E->G and A->D->F->G. Suppose we process the former of these, with a flow of one:

Flow

Residual

Now, there is only one minimum hop path through the residual: A->D->F->G, with a flow of two:

Flow

Residual

At this point, there are only two paths through the residual: A->B->C->D->F->G and A->B->C->E->D->F->G. The first of these has fewer hops, so we process it. It has a flow of two:

Flow

Residual

The final path through the residual is A->B->C->E->D->F->G with a flow of one. When we process it, we get the same flow and residual graphs as the other two algorithms:

Flow

Residual


Bottom Lines

We've shown three ways to calculate the augmenting paths. Each way yields a different ordering of augmenting paths; however, all three ways lead to the same flow and residual. They differ in what they try to optimize: There's no nice closed form solution for either the greedy DFS or the Modified Dijkstra algorithm. When we evaluate performance, the greedy DFS is significantly slower, and Modified Dijkstra runs on par with Edmonds-Karp. Edmonds Karp does have a closed form running time: O(|V||E|2).

One thing that you should remember about network flow is that it is quite a bit slower than all of the other graph algorithms we've studied so far.


Finding the Minimum Cut

As detailed in the Topcoder tutorial, you can use the final residual graph to find the minimum cut. First, you find all nodes reachable from the source in the residual graph. This is one set of nodes, which we color purple below:

Now, in the original graph, we divide our nodes into two sets: the set determined above, and all of the remaining nodes. They are drawn purple and yellow in the original graph below:

The minimum cut is composed of all the edges that go from the source set to the sink set. These are edges AD, CD and EG, which I've drawn in red above. The sum of their capacities equals the maximum flow of six.