Download - Maximum Flow Computation Programming Puzzles and Competitions CIS 4900 / 5920 Spring 2009
Maximum Flow Maximum Flow ComputationComputation
Maximum Flow Maximum Flow ComputationComputation
Programming Puzzles and CompetitionsProgramming Puzzles and CompetitionsCIS 4900 / 5920CIS 4900 / 5920
Spring 2009Spring 2009
Outline
• Flow analysis• The min-cut and max-flow
problems• Ford-Fulkerson and Edmonds-Karp
max-flow algorithms• Start of an example problem from
ICPC’07 (“Tunnels”)
Flow Network
• Directed graph G = (V, E) with– edge capacities c(u,v) ≥ 0– a designated source node s– a designated target/sink node t– flows on edges f(u,v)
Flow Constraints
s
b
t
a
5
4
1|3
1|1
1|2
f(s,a) = 1 f(a,s) = -1f(a,b) = 1 f(b,a) = -1f(b,t) = 1 f(t,b) = -1
capacity: f(u,v) ≤ c(u,v)symmetry: f(u,v) = -f(v,u)
conservation:
Vvt}{s,Vu
v)f(u,
Applications
• fluid in pipes• current in an electrical circuit• traffic on roads• data flow in a computer network• money flow in an economy • etc.
Maximum Flow Problem
Assuming– source produces the material at a
steady rate– sink consumes the material at a steady
rate
What is the maximum net flow from s to t?
Ford-Fulkerson Algorithm
• Start with zero flow• Repeat until convergence:
– Find an augmenting path, from s to t along which we can push more flow
– Augment flow along this path
Residual Capacity
• Given a flow f in network G = (V, E)• Consider a pair of vertices u, v є V• Residual capacity =
amount of additional flow we can push directly from u to v cf (u, v) = c(u, v) f (u, v)
≥ 0 since f (u, v) ≤ c(u, v)
• Residual network Gf = (V, Ef ) Ef = { (u, v) є V ×V | cf (u, v) > 0 }
• Example:c(u,v) = 16, f(u,v) = 5 cf (u, v) = 11
s
b
t
a
5
1|4
1|1
2|2
1|3
s
b
t
a
5
1|4
1
1|1
1
2
1
residual graph, with flow-augmenting path
original graphwith new flow
Example (3)
s
b
t
a
5
1|4
1|1
2|2
1|3
original graph with new flow
new residual graph
s
b
t
a
5
3
1
2
2
1
1
Example (4)
s
b
t
a
1|5
2|4
1
2|2
1|3
s
b
t
a
5
3
1
2
2
1
new residual graph, with augmenting path
1
original graphwith new flow
Example (5)
s
b
t
a
1|5
2|4
1
2|2
1|3
original graph with new flow
new residual graph
s
b`
t
a
4
2
1
2
2
2
11
Example (6)
s
b
t
a
2|5
2|4
1
2|2
3|3
new residual graph, with augmenting path
original graphwith new flow
s
b
t
a
4
2
1
2
2
2
11
Example (7)
s
b
t
a
2|5
2|4
1
2|2
3|3
original graph, with new flow
residual graph(maximum flow = 5)
Example (8)
s
b
t
a
2
2
1
2
2
3
2
Ford-Fulkerson Algorithm
for (each edge (u,v) є E[G]) f[u][v] = f[v][u] = 0;while ( path p from s to t in Gf) {
cf(p) = min {cf(u,v) | (u,v) є p};
for (each edge (u,v) є p) { f[u][v] = f[u][v] + cf(p)
f[v][u] = -f[u][v] }}
O(E)
O(E)
O(E x f*)
f* = maximum flow, assuming integer flows, since each iteration increases flow by at least one unit
int findMaxFlow (int s, int t) { int result = 0; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) flow[i][j] = 0; for (;;) { int Increment = findAugmentingPath(s, t); if (Increment == 0) return result; result += capTo[t]; int v = t, u; while (v != s) { // augment flow along path u = prev[v]; flow[u][v] += capTo[t]; flow[v][u] -= capTo[t]; v = u; }}}
static int findAugmentingPath(int s, int t) { for (int i = 0; i < n; i++) { prev[i] = -1; capTo[i] = Integer.MAX_VALUE;} int first = 0, last = 0; queue[last++] = s; prev[s] = -2; // s visited already while (first != last) { int u = queue[first++]; for (int v = 0; v < n; v++) { if (a[u][v] > 0) { int edgeCap = a[u][v] - flow[u][v]; if ((prev[v] == -1) && (edgeCap > 0)) { capTo[v] = Math.min(capTo[u], edgeCap); prev[v] = u; if (v == t) return capTo[v]; queue[last++] = v; }}}} return 0;}
This uses breadth-first search, which is the basisof the Edmonds-Karp algorithm.
Example: Finding Augmenting Path
v0
v2
v3
v1
v4
v5
v6
v7
source
queue = { v0 }
target1|3
1|3 1|4
2/3
1|13
2|4
3
2
1
3
1
1
∞
1 = capTo
= prev
Application to Augmenting Path
v0
v2
v3
v1
v4
v5
v6
v7
source
queue = { v1, v2 }
target1|3
1|3 1|4
2/3
1|13
2|4
3
2
1
3
1
1
∞
2
2
Application to Augmenting Path
v0
v2
v3
v1
v4
v5
v6
v7
source
queue = {v2}
target1|3
1|3 1|4
2/3
1|13
2|4
3
2
1
3
3
1
∞
2
2
Application to Augmenting Path
v0
v2
v3
v1
v4
v5
v6
v7
source
queue = {v3}
target1|3
1|3 1|4
2/3
1|13
2|4
3
2
1
3
3
1
∞
2
2
2
Application to Augmenting Path
v0
v2
v3
v1
v4
v5
v6
v7
source
queue = {v4, v5}
target1|3
1|3 1|4
2/3
1|13
2|4
3
2
1
3
1
1
∞
2
1
1
2
1
Application to Augmenting Path
v0
v2
v3
v1
v4
v5
v6
v7
source
queue = { v5, v6 }
target1|3
1|3 1|4
2/3
1|13
2|4
3
2
1
3
1
1
∞
2
1
1
2
1
1
Done
Breadth-first search
• The above is an example• Depth-first search is an alternative• The code is nearly the same• Only the queuing order differs
static int findAugmentingPath(int s, int t) { for (int i = 0; i < n; i++) { prev[i] = -1; capTo[i] = Integer.MAX_VALUE;} int first = 0, last = 0; queue[last++] = s; prev[s] = -2; // s visited already while (first != last) { int u = queue[last--]; for (int v = 0; v < n; v++) { if (a[u][v] > 0) { int edgeCap = a[u][v] - flow[u][v]; if ((prev[v] == -1) && (edgeCap > 0)) { capTo[v] = Math.min(capTo[u], edgeCap); prev[v] = u; if (v == t) return capTo[v]; queue[last++] = v; }}}} return 0;}
This uses depth-first search.
Breadth vs. Depth-first Search
• Let s be the start node
ToVisit.make_empty; ToVisit.insert(s); s.marked = true;
while not ToVisit.is_empty { u = ToVisit.extract; for each edge (u,v) in E if not u.marked { u.marked = true; ToVisit.insert(u);}}
If Bag is a FIFO queue, we get breadth-first search;if LIFO (stack), we get dept-first.