max flows, min cuts, and the Ford-Fulkerson method
Min cuts and max flows
Set up
-
A directed graph , and edge capacities
-
A source and a sink , has only outgoing edges, has only incoming edges
An s-t cut is a partition of into and such that and .
An edge crosses the cut if it goes from s's side to t's side.
The cost (or capacity) of the cut is the sum of the capacities of the edges that cross the cut.
A minimum s-t cut is an s-t cut whose cost is minimum over all s-t cuts.
Flows
-
In addition to a capacity, each edge has a flow
-
the flow on an edge can't exceed the capacity of the edge
-
At each vertex, the incoming flows must equal the outgoing flows, except at and
A maximum flow is a flow of maximum value.
Theorem: Max-flow min-cut theorem
- The value of the maximum flow is equal to the capacity of the minimum cut.
The Ford-Fulkerson algorithm
-
Outline
- We wiil be updating a flow f
- start with f being the zero flow
- We will maintain a "residual graph" that indicates how we can change f to get a flow with larger value
- A path from s to t in will give us a way to increase the flow value
- we will continue until there is no path from s to t in
Tool: Residual networks
- Given a flow and graph , the forward edge has weight[capacity]-[flow], the backward edge has weight[flow]. (Forward edges are the amount of capacity left, backward edges are the amount of flow that can be removed)
Residual networks tell us how to improve the flow.
-
Definition: A path from s to t in the residual network is called an augmenting path.
-
Claim: If there is an augmenting path, then f is not a maximum flow.
-
Easy case: all edges on the path are forward edges, just increase the flow on all the edges by the same amount, then update the residual network.
-
Harder case: some edges on the path are backward edges, we need to decrease the flow on those edges. Decrease the flow on all the backward edges by the same amount, then update the residual network.
-
increaseFlow(path P in , flow f): -x = min of the capacities of the edges on P
-
for (u,v) in P:
-
if(u,v) is a forward edge:
- f(u,v) += x
-
else:
- f(v,u) -= x
-
-
return f
-
-
Ford-Fulkerson algorithm
Ford-Fulkerson(G, s, t):
f = 0
G_f = G
while t is reachable from s in G_f:
P = any s-t path in G_f
f = increaseFlow(P, f)
G_f = residual network of f
return f
Edmonds-Karp algorithm
-
The Ford-Fulkerson algorithm is correct, but it can be slow
-
Edmonds-Karp algorithm: always choose the shortest augmenting path in the residual network using BFS
-
The running time is
Applications
Maximum bipartite matching
-
A bipartite graph is a graph whose vertices can be divided into two disjoint sets and such that every edge connects a vertex in to a vertex in .
-
A matching is a subset of edges in which no vertex appears more than once.
-
A maximum matching is a matching of maximum size.
Assignment problem
One set X, Another set Y, each x in X can participate in c(x) matches, each y in Y can participate in c(y) matches, each pair (x,y) can only be matched c(x,y) times.
Find a maximum matching.
code template
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
// the number of vertices
const int N = 20;
//reading the graph
void read_graph(int graph[N][N], int n)
{
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> graph[i][j];
}
// BFS
bool bfs(int rGraph[N][N], int s, int t, int parent[]){
bool visited[N];
memset(visited, 0, sizeof(visited));
queue<int> q;
q.push(s);
visited[s] = true;
parent[s] = -1;
while (!q.empty()){
int u = q.front();
q.pop();
for (int v = 0; v < N; v++){
if (visited[v] == false && rGraph[u][v] > 0){
q.push(v);
parent[v] = u;
visited[v] = true;
}
}
}
return (visited[t] == true);
}
int fordfulkerson(int graph[N][N], int s, int t){
int u, v;
int rGraph[N][N]; // residual graph
// initialize residual graph
for (u = 0; u < N; u++)
for (v = 0; v < N; v++)
rGraph[u][v] = graph[u][v];
int parent[N]; // store the path
int max_flow = 0; // max flow
// BFS
while (bfs(rGraph, s, t, parent)){
int path_flow = INT_MAX;
for (v = t; v != s; v = parent[v]){
u = parent[v];
path_flow = min(path_flow, rGraph[u][v]);
}
// update residual capacities of the edges and reverse edges along the path
for (v = t; v != s; v = parent[v]){
u = parent[v];
rGraph[u][v] -= path_flow;
rGraph[v][u] += path_flow;
}
// add path flow to overall flow
max_flow += path_flow;
}
return max_flow;
}
Comments
Post a Comment