关于网络流和最大流
这是一种非常神奇 (毒瘤) 的算法,可以用来解决很多稀奇古怪的问题和限制条件(当然建模是难点),并跑出各种不可思议的时间复杂度。
在网络流中,一个有向图有且仅有一个源点
S
S
S和一个汇点
T
T
T,每条有向边可以看成一根有流量为
f
f
f的水流过的容量上限为
c
c
c的定向水管,其中
0
≤
f
≤
c
0≤f≤c
0≤f≤c。
除
S
S
S和
T
T
T外每个点的流入量都要
=
=
=每个点的流出量,
S
S
S的净流出量
=
T
=T
=T的净流入量。
而最普通的最大流问题即是询问一张网络图中从
S
S
S到
T
T
T能流出的最大流量
以下内容参考自
N
i
r
o
B
C
NiroBC
NiroBC大神
关于暴力算法
每次找出一条从源点到汇点的由未流满的边组成的路径,使得该路径每条边流量增加同一个数。这样的路径叫增广路。
不断找增广路,直到找不出增广路。
需要注意的是,每发现一条增广路,所有这条增广路使用过的边的反向边的剩余容量需要加上流过的流量。因为之后的增广路可能会反着走这条边。
关于奇妙的 D i n i c Dinic Dinic
做法
重复以下过程:
1.
1.
1. 用
b
f
s
bfs
bfs 对每个点
u
u
u 求出,从
S
S
S开始只经过未流满的边走到该点,至少需要走过的边数,记作
d
e
p
u
dep_u
depu。
2.
2.
2. 只经过由深度为
d
e
p
dep
dep的点走向深度为
d
e
p
+
1
dep+1
dep+1的边,找出这种情况下所有的增广路。
Dinic 的时间复杂度
首先,
b
f
s
bfs
bfs 最多进行
O
(
n
)
O(n)
O(n) 次,因为每一轮
b
f
s
bfs
bfs 后的
d
e
p
T
dep_T
depT 都是严格单调递增的。
每一次
d
f
s
dfs
dfs 后,对于同一张分层图,我们可以用最多
O
(
n
m
)
O(nm)
O(nm) 的时间找出所有增广路。
所以总时间复杂度
O
(
n
2
e
)
O(n^2e)
O(n2e)。
代码实现
#include <queue>
#include <cstdio>
using namespace std;
const int maxn = 10005;
const int maxe = 100005;
const int oo = 2000000000;
int n;
int edge_cnt;
struct edge {int nxt, to, val;} E[maxe << 1];
int fir[maxn];
int s, t;
int dep[maxn], fl[maxn];
int min(int x, int y) {return x < y ? x : y;}
int read() {
char ch = getchar(); bool f = 1;
while(ch < '0' || ch > '9') f &= ch != '-', ch = getchar();
int res = 0;
while(ch >= '0' && ch <= '9') res = (res << 3) + (res << 1) + (ch ^ 48), ch = getchar();
return f ? res : -res;
}
void clear_edge() {
edge_cnt = 1;
for(int i = 1; i <= n; i++) fir[i] = 0;
}
void add_edge(int u, int v, int val) {
E[++edge_cnt] = (edge) {fir[u], v, val};
fir[u] = edge_cnt;
}
bool bfs() {
for(int i = 1; i <= n; i++) dep[i] = oo;
queue<int> q;
q.push(s);
dep[s] = 0;
while(!q.empty()) {
int u = q.front(); q.pop();
for(int e = fir[u]; e; e = E[e].nxt) {
int v = E[e].to;
if(!E[e].val || dep[v] < oo) continue;
dep[v] = dep[u] + 1;
q.push(v);
}
}
return dep[t] < oo;
}
int dfs(int u, int f) {
if(u == t) return f;
fl[u] = 0;
for(int e = fir[u]; e; e = E[e].nxt) {
int v = E[e].to;
if(!E[e].val || dep[v] != dep[u] + 1) continue;
int got = dfs(v, min(f, E[e].val));
if(!got) continue;
f -= got;
fl[u] += got;
E[e].val -= got;
E[e ^ 1].val += got;
if(!f) return fl[u];
}
return fl[u];
}
int Dinic() {
int res = 0;
while(bfs()) res += dfs(s, oo);
return res;
}
int main() {
n = read();
int m = read();
s = read(), t = read();
clear_edge();
while(m--) {
int u = read(), v = read(), val = read();
add_edge(u, v, val), add_edge(v, u, 0);
}
printf("%d\n", Dinic());
return 0;
}