【图论】Dinic算法
验证链接:[洛谷P3376 - 网络最大流] | [洛谷P1361 - 小M的作物] | [洛谷P3386 - 二分图最大匹配]
设点数为 \(n\) ,边数为 \(m\) ,那么Dinic算法的时间复杂度是 \(O(n^2m)\) ,在稀疏图上效率和EK算法相当,但在稠密图上效率要比EK算法高很多。
同时使用了多路增广、当前弧优化、可行性剪枝。
当前弧优化:把边的头cur[u]设为引用,只有当in=0(当前u点入流量耗尽)时不优化,其余情况是v节点出流量耗尽,下次跳过边u->v(当in=0时跳过当前弧,会造成负优化)。
可行性剪枝:当一个点出流量为0,意味着他与T不连通,把他从分层图删除。
struct Dinic {
static const int MAXN = 2e5 + 10;
static const int MAXM = 4e6 + 10;
int n, m, s, t;
struct Edge {
int v, nxt;
ll flow;
} e[MAXM];
int h[MAXN];
int que[MAXN], dep[MAXN], cur[MAXN];
bool BFS() {
memset(dep, 0, sizeof(dep[0]) * (n + 1));
memcpy(cur, h, sizeof(cur[0]) * (n + 1));
int l = 1, r = 0;
que[++r] = s, dep[s] = 1;
while(l <= r) {
int u = que[l++];
for(int i = h[u]; i; i = e[i].nxt) {
if(e[i].flow && !dep[e[i].v])
dep[e[i].v] = dep[u] + 1, que[++r] = e[i].v;
}
}
return dep[t];
}
ll DFS(int u, ll in) {
if(u == t)
return in;
ll out = 0;
for(int &i = cur[u]; i; i = e[i].nxt) {
if(e[i].flow && dep[u] + 1 == dep[e[i].v]) {
ll res = DFS(e[i].v, min(in, e[i].flow));
e[i].flow -= res, in -= res;
e[i ^ 1].flow += res, out += res;
if(in == 0)
break;
}
}
if(out == 0)
dep[u] = 0;
return out;
}
void Init(int n, int s, int t) {
this->n = n, m = 1, this->s = s, this->t = t;
for(int i = 1; i <= n; ++i)
h[i] = 0;
}
void AddEdge(int u, int v, ll w) {
e[++m] = {v, h[u], w}, h[u] = m;
e[++m] = {u, h[v], 0}, h[v] = m;
}
ll Maxflow() {
ll flow = 0;
while(BFS())
flow += DFS(s, LINF);
return flow;
}
} dinic;