Flow Intro PDF
Flow Intro PDF
1 Problem
Network flow is an advanced branch of graph theory. The problem resolves around a special type of
weighted directed graph with two special vertices: the source vertex, which has no incoming edge,
and the sink vertex, which has no outgoing edge. By convention, the source vertex is usually labelled
s and the sink vertex labelled t.
The story usually go like this: there are a bunch of junctions (nodes in the graph) and a bunch of
pipes (edges in the graph) connecting the junction. The pipe will only allow water to flow one way
(the graph is directed). Each pipe has also has a capacity (the weight of the edge), representing the
maximum amount of water that can flow through the pipe. Finally, we pour an infinite amount of
water into the source vertex. The problem is to find the maximum flow of the graph - the maximum
amount of water that will flow to the sink. Below is an example of a network flow graph:
0/2 0/4
s 0/3 t
0/4
0/2
b
Figure 1: A simple network flow graph. There are currently no water flowing.
It is fairly easy to see that the maximum flow in the above figure is 6. We can flow 2 units of water
from s a t, 2 units of water from s b a t, and 2 units of water from s b t. This
gives a flow of 6 and since all incoming edge to the sink are saturated, this is indeed the maximum
flow. Note that in the example, not all pipe are saturated with water.
0/2 3/4
s 3/3 t
3/4
0/2
b
Now we have run into a problem: our only options left are to push 1 unit of water along the path
s a t and 1 unit of water along s b t. After that, we wont be able to find any more path
from s to t! Yet, we have only found 5 flow, which is not he maximum flow. Thus, the idea is not
optimal since it depends on how we picked our path. While we can try to find a good path-picking
algorithm, it would be nice if the algorithm is not dependent on the paths we chose.
A crucial observation is that there is actually another path from s to t other than the two that we
mentioned above! Suppose we redirect 2 units of water from b a t to b t, this will decrease
the amount of water running through the pipe (a, t) to 0. Now we have a path from s a t in
which we can flow 2 units of water! The graph now looks as follows:
2/2 3/4
s 1/3 t
3/4
2/2
b
Figure 3: The bolded edge indicate which pipe has their flow adjusted.
It is now easy to see that we can push 1 unit of water along s b a t to obtain the
maximum flow of 6. If we carefully study the above figure, what we have essentially done is to flow
2 unit of water along s a, and then push back 2 unit of water from a b, and finally redirect
the pushed back flow along b t to the sink. So the key to completing the algorithm is the idea of
pushing back flow - if we have x units of water flowing in the pipe (u, v), then we can pretend there
is a pipe (v, u) with capacity x when we are trying to find a path from s to t.
This is the concept of residual graph. The residual graph of a network flow is essentially the
network graph except that for every edge (u, v) that currently carries x unit of water, there is an
edge (v, u) with capacity x in the residual graph. The following figure shows the residual graph after
finding our first path:
a
0/2 3/4
s 3/3 t
3/4
0/2
b
Figure 4: The dashed edges are the edges we added in the the residual graph. The capacity of the
dashed edge is the same as the amount of water carried by the solid edge in the opposite direction.
So here is an algorithm to find the maximum flow: First construct the residual graph (in the
beginning, the residual graph is the same as the network graph). While there exists a path from s to t
in the residual graph, we flow water through one of the path (a path in the a residual graph is called
an augmenting path). We then adjust the residual graph accordingly. Once we can no longer find
any more path in the residual graph, we have found the maximum flow. This algorithm known as the
Ford Fulkerson Method and its correctness is dependent on the following theorem, which we shall
not prove:
Theorem 2.1. If the residual graph contains no more augmenting path, then we have found the max-
imum flow.
/ / r e t u r n t r u e i f f an a u g m e n t i n g p a t h e x i s t s i n t h e r e s i d u a l g r a p h
bool f i n d a u g m e n t i n g p a t h ( ) {
memset ( p a r e n t , 1, s i z e o f ( p a r e n t ) ) ;
memset ( s e e n , 0 , s i z e o f ( s e e n ) ) ;
queue<i n t > q ;
q . p u s h ( SRC ) ;
s e e n [ SRC ] = t r u e ;
w h i l e ( ! q . empty ( ) ) {
i n t c u r = q . f r o n t ( ) ; q . pop ( ) ;
i f ( c u r == SNK) r e t u r n t r u e ;
f o r ( i n t i = 0 ; i <= SNK ; ++ i ) {
i f ( ! s e e n [ i ] && c a p a c i t y [ c u r ] [ i ] ) {
seen [ i ] = true ;
parent [ i ] = cur ;
q . push ( i ) ;
}
}
}
return f a l s e ; / / did not f i n d a path to the sink
}
/ / t h e main f u n c t i o n t o s o l v e max f l o w
i n t max flow ( ) {
i n t maxflow = 0 ;
while ( find augmenting path ( ) ) {
i n t flow = t r a c e a u g m e n t i n g p a t h ( ) ;
maxflow += f l o w ;
a d j u s t c a p a c i t y ( flow ) ;
}
r e t u r n maxflow ;
}
4 Ford Fulkerson with DFS
We can also use DFS to find augmenting path in the Ford Fulkerson method. While there are not
guaranteed improvement on the time complexity, it does make the code a lot shorter since we can
keep track of how much flow to push in the augmenting path and adjust the residual graph in the same
recursive call. Implementation as follow (uses the same variable as above):
i n t f i n d a u g m e n t i n g p a t h ( i n t cur , i n t c u r f l o w ) {
i f ( c u r == SNK) r e t u r n c u r f l o w ;
seen [ cur ] = true ;
f o r ( i n t i = 0 ; i <= SNK ; ++ i ) {
i f ( ! s e e n [ i ] && c a p a c i t y [ c u r ] [ i ] ) {
/ / f i n d how much f l o w we can p u s h t h r o u g h i n a u g m e n t i n g p a t h
i n t amt = min ( c u r f l o w , c a p a c i t y [ c u r ] [ i ] ) ;
i f ( flow > 0) {
/ / found augmenting path
c a p a c i t y [ c u r ] [ i ] = f l o w ;
c a p a c i t y [ i ] [ c u r ] += f l o w ;
return flow ;
}
}
}
return 0;
}
i n t max flow ( ) {
i n t maxflow = 0 , f l o w = 0 ;
do {
memset ( s e e n , 0 , s i z e o f ( s e e n ) ) ;
f l o w = f i n d a u g m e n t i n g p a t h ( SRC , INF ) ;
maxflow += f l o w ;
} while ( flow > 0 ) ;
r e t u r n maxflow ;
}