最大流问题:给出一个联通的不带边权的有向图,给出源点s和汇点t,将边当作一条有容量限制(单位时间内只能流固定容量的水)的带方向(水流只能从向边的方向流动)的水管。求解单位时间内从s到t最多能流动多少水量。
Ford-Fulkerson算法:
算法实现:
const int INF = 0x3f3f3f3f;
const int MAX_V = 300;
struct edge {
int to, cap, rev;
};
vector<edge> G[MAX_V];
bool used[MAX_V];
void add_edge(int from, int to, int cap) {
G[from].push_back((edge){to, cap, G[to].size()});
G[to].push_back((edge){from, 0, G[from].size() - 1});
}
int dfs(int v, int t, int f) {
if(v == t) return f;
used[v] = true;
for(int i = 0; i < G[v].size(); i++) {
edge &e = G[v][i];
if(!used[e.to] && e.cap > 0) {
int d = dfs(e.to, t, min(f, e.cap));
if(d > 0) {
e.cap -= d;
G[e.to][e.rev].cap += d;
return d;
}
}
}
return 0;
}
int max_flow(int s, int t) {
int flow = 0;
for(;;) {
memset(used, 0, sizeof(used));
int f = dfs(s, t, INF);
if(f > 0) flow += f;
else {
return flow;
}
}
}
证明:摘自http://www.cnblogs.com/rainydays/archive/2011/03/03/1969543.html
const int INF = 0x3f3f3f3f;
const int MAX_V = 1000;
int V; // 顶点数
vector<int> G[MAX_V]; // 图的邻接表表示
int match[MAX_V]; // 所匹配的顶点
bool used[MAX_V]; // DFS中用到的访问标记
// 向图中增加一条连接u和v的边
void add_edge(int u, int v) {
G[u].push_back(v);
G[v].push_back(u);
}
// 通过DFS寻找增广路
bool dfs(int v) {
used[v] = true;
for(int i = 0; i < G[v].size(); i++) {
int u = G[v][i], w = match[u];
if(w < 0 || !used[w] && dfs(w)) {
match[v] = u;
match[i] = v;
return true;
}
}
return false;
}
int bipartite_matching() {
int res = 0;
memset(match, -1, sizeof(match));
for(int v = 0; v < V; v++) {
if(match[v] < 0) {
memset(used, 0, sizeof(used));
if(dfs(v)) {
res++;
}
}
}
return res;
}
const int INF = 0x3f3f3f3f;
const int MAX_V = 1000;
struct edge { int to, cap, cost, rev; };
int V; //顶点数
vector<edge> G[MAX_V]; //图的邻接表示
int dist[MAX_V]; //最短距离
int prevv[MAX_V], preve[MAX_V]; //最短路中的前驱节点和对应的边
void add_edge(int from, int to, int cap, int cost) {
G[from].push_back((edge){to, cap, cost, G[to].size()});
G[to].push_back((edge){from, 0, -cost, G[from].size() - 1});
}
int min_cost_flow(int s, int t, int f) {
int res = 0;
while(f > 0) {
//Bellman-Ford
fill(dist, dist + V, INF);
dist[s] = 0;
bool update = true;
while(update) {
update = false;
for(int v = 0; v < V; v++) {
if(dist[v] == INF) continue;
for(int i = 0; i < G[v].size(); i++) {
edge &e = G[v][i];
if(e.cap > 0 && dist[e.to] > dist[v] + e.cost) {
dist[e.to] = dist[v] + e.cost;
prevv[e.to] = v;
preve[e.to] = i;
update = true;
}
}
}
}
if(dist[t] == INF) {
return -1;
}
int d = f;
for(int v = t; v != s; v = prevv[v]) {
d = min(d, G[prevv[v]][preve[v]].cap);
}
f -= d;
res += d * dist[t];
for(int v = t; v != s; v = prevv[v]) {
edge &e = G[prevv[v]][preve[v]];
e.cap -= d;
G[e.to][e.rev].cap += d;
}
}
return res;
}
const int MAX_V = 1000;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> P;
struct edge { int to, cap, cost, rev; };
int V; //顶点数
vector<edge> G[MAX_V]; //图的邻接表示
int h[MAX_V]; //顶点的势
int dist[MAX_V]; //最短距离
int prevv[MAX_V], preve[MAX_V]; //最短路中的前驱节点和对应的边
void add_edge(int from, int to, int cap, int cost) {
G[from].push_back((edge){to, cap, cost, G[to].size()});
G[to].push_back((edge){from, 0, -cost, G[from].size() - 1});
}
// 求解从s到t流量为f的最小费用流
// 如果没有流量为f的流,则返回-1
int min_cost_flow(int s, int t, int f) {
int res = 0;
fill(h, h + V, 0); //初始化h
while(f > 0) {
// 使用Dijkstra算法更新h
priority_queue<P, vector<P>, greater<P> > que;
fill(dist, dist + V, INF);
dist[s] = 0;
que.push(P(0, s));
while(!que.empty()) {
P p = que.top(); que.pop();
int v = p.second;
if(dist[v] < p.first) continue;
for(int i = 0; i < G[v].size(); i++) {
edge &e = G[v][i];
if(e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]) {
dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
prevv[e.to] = v;
preve[e.to] = i;
que.push(P(dist[e.to], e.to));
}
}
}
if(dist[t] == INF) {
// 不能再增广
return -1;
}
for(int v = 0; v < V; v++) h[v] += dist[v]; //因为加入了势,此时dist[v]是最短距离加上 h[s] - h[v],
//因为h[s]恒为0, 所以这样就能保证 h[v] 总为s到v的最短距离。
// 沿s到t的最短路尽量增广
int d = f;
for(int v = t; v != s; v = prevv[v]) {
d = min(d, G[prevv[v]][preve[v]].cap);
}
f -= d;
res += d * h[t];
for(int v = t; v != s; v = prevv[v]) {
edge &e = G[prevv[v]][preve[v]];
e.cap -= d;
G[v][e.rev].cap += d;
}
}
return res;
}