网络流——最大流——Dinic算法的初步认识
关于网络流——最大流
简单说一说:有一个起点(源点),和一个终点(汇点),它们之间用很多直径大小不一的管子连在一起,为什么要用大小不一的管子,(假如这些都是水管),那么你要做的就是:算出从源点到汇点最大可以流入多少水。
显然,对于一条路上,它的最大流是这条路上直径最小的管子所能承受的水量(再多的话,那最小的水管就爆了)。 于是乎,直径最小的水管就被占满了——不能再有更多的水从这里通过,而直径比它大的管子还没被占满——所以他们还可以再让更多的水通过。
大概就这么个意思_如下图

最后,把所有到达汇点的水量加起来就行了。
例题:--> #2634 最大流模板
描述
给定 n 个点,m 条边,给定每条边的容量,求从点 s 到点 t的最大流。
输入
第一行四个整数 n、 m、s、t。 接下来的 m 行,每行三个整数 u、v 、c,表示 u 到 v,流量为 c 的一条边。
输出
输出点 s到点t 的最大流。
样例:
样例输入 7 14 1 7 1 2 5 1 3 6 1 4 5 2 3 2 2 5 3 3 2 2 3 4 3 3 5 3 3 6 7 4 6 5 5 6 1 6 5 1 5 7 8 6 7 7 样例输出 14
那么下面,上代码::::
CODE
#include <bits/stdc++.h> using namespace std; const int INF = 0xfffffff; const int MAXN = 5200199; int s, t, n, m; int tot = 1; int first[MAXN]; int dep[MAXN]; struct node { int from, to, v; int nxt; }; node edge[MAXN * 2]; void add(int u, int v, int w) { tot++; edge[tot].from = u; edge[tot].to = v; edge[tot].v = w; edge[tot].nxt = first[u]; first[u] = tot; } bool bfs() //建立分层图,每次dfs就是在最新的分层图的基础上进行的 { memset(dep, -1, sizeof(dep)); dep[s] = 0; queue<int> q; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); for (int i = first[u]; i; i = edge[i].nxt) { int j = edge[i].to; if (dep[j] == -1 && edge[i].v) { dep[j] = dep[u] + 1; q.push(j); } } } return dep[t] != -1; } int dfs(int u, int flow) //以u记录当前编号,flow记录目前的最大流 { if (u == t) { return flow; } int delta = flow; // !!重点,以delta记录 向下传递的最大流 与 实际接收的最大流 的差。 -->其实就是INF与最后答案的差 for (int i = first[u]; i; i = edge[i].nxt) { int to = edge[i].to; int w = edge[i].v; if ((dep[to] == dep[u] + 1) && (w > 0)) { int sum = dfs(to, min(delta, w)); if (!sum) { dep[to] = INF; // 如果已经搜到这条边的剩余流量为0,那么就标记这个点不可再走了 } edge[i].v -= sum; edge[i ^ 1].v += sum; //正向和反向边处理 delta -= sum; //看最下面的图 if (!delta) { break; //如果没有剩余流量,就推出 } } } return flow - delta; //最后结果 } int Read() { int f = 1, k = 0; char c = getchar(); while (c != '-' && (c < '0' || c > '9')) { c = getchar(); } if (c == '-') { f = -1; c = getchar(); } while (c >= '0' && c <= '9') { k = (k << 3) + (k << 1) + c - 48; c = getchar(); } return f * k; } int main() { freopen("#2634.in", "r", stdin); n = Read(); m = Read(); s = Read(); t = Read(); int u, v, w; for (int i = 1; i <= m; i++) { u = Read(); v = Read(); w = Read(); add(u, v, w); add(v, u, 0); } long long ans = 0; while (bfs()) ans += dfs(s, INF); printf("%lld\n", ans); return 0; }
对于delta的解释:如图
其实delta就是阴影部分,最后答案就是最上面一层(flow)减去阴影(delta)--> flow-delta,——蓝色是下面的delta往上返回得到的。

最后,这是本人对于此算法的初步理解,如有不正确的欢迎讨论!
还有一个小问题,据说 当前弧优化 有时会出问题?(我们老师说的) 哪位大佬能帮忙解解惑呀

浙公网安备 33010602011771号