算法步骤:
- 从源点开始,用BFS找一条最短的增广路径,计算该路径上的残量最小值,累加到最大流值;
- 沿着该路径修改流量值,实际是修改是残量网络的边权;
- 重复上述步骤,直到找不到增广路时,此时得到的流就是最大流。
时间复杂度: O ( n m 2 ) O(nm^2) O(nm2), n n n是点数, m m m是边数。
但实际情况中,EK算法的复杂度远低于理论上的复杂度,一般 1000 1000 1000~ 10000 10000 10000的规模EK算法都可以解决。
模板题:
Acwing2171.EK求最大流
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int N = 1010, M = 20010; //存两个方向的边,M开2倍
int n, m, S, T;
int idx, head[N], e[M], ne[M], c[M]; //c是容量
int q[N], d[N], pre[N]; //q模拟队列, d是从源点到当前路径中所经过的最小容量, pre该点是由那一条边转移过来的
bool vis[N];
void add(int u, int v, int w) //维护的图是残留网络,建立双向边
{
e[idx] = v, c[idx] = w, ne[idx] = head[u], head[u] = idx ++;
e[idx] = u, c[idx] = 0, ne[idx] = head[v], head[v] = idx ++;
}
bool bfs()
{
int hh = 0, tt = -1;
memset(vis, 0, sizeof vis);
q[++ tt] = S; //放入起点S
vis[S] = true, d[S] = INF;
while(hh <= tt)
{
int u = q[hh ++];
for(int i = head[u]; ~i; i = ne[i])
{
int v = e[i];
if(vis[v] || c[i] == 0) continue; //容量==0是不能走的
pre[v] = i; //这里记录的是边,不是点!
d[v] = min(d[u], c[i]);
if(v == T) return true; //走到了终点
q[++ tt] = v; vis[v] = true; //将v加入队列
}
}
return false;
}
int EK()
{
int r = 0;
while(bfs())
{
r += d[T];
for(int i = T; i != S; i = e[pre[i] ^ 1]) //将S->T的路径经过的边的权值更新
c[pre[i]] -= d[T], c[pre[i] ^ 1] += d[T];
}
return r;
}
int main()
{
#ifdef LOCAL
freopen("in.in", "r", stdin);
freopen("out.out", "w", stdout);
#endif
memset(head, -1, sizeof head);
scanf("%d%d%d%d", &n, &m, &S, &T);
while(m --)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
}
printf("%d\n", EK());
return 0;
}