网络流
网络,是指一个有向带权图,并且有两个特别的点——源点与汇点。
对于流 \(f_{u,v}\),满足以下三个条件
- 容量限制:对于每条边,流量不超过其容量。
- 斜对称性:每条边与其反边流量之和为 \(0\),即 \(f_{u,v}=-f_{v,u}\)。
- 流守恒性:从源点流出量等于汇点流入量。
最大流
最大流问题是给定一个网络,求源点到汇点的最大流量。
\(Ford-Fulkerson\) 算法
寻找一条最短路,选出整条路径上的最小值 \(x\) 作为流量,把每条边的容量减小 \(x\),并建立反边并加以合并,如此往复。该算法每执行一次就需要 \(m\) 的时间复杂度,最多会执行 \(ans\) 次,所以时间复杂度最坏为 \(ans\times m\)。
\(Edmonds-Karp\) 算法
\(Edmonds-Karp\) 算法实质就是对 \(Ford-Fulkerson\) 的优化,将查找可行路径的方法改为了将所有边权视为 \(1\),跑最短路只需要 \(BFS\),于是时间复杂度降为 \(nm^2\)。
\(Dinic\) 算法
\(Dinic\) 算法每次将点分为几层,连边时只连跨层的边,执行 \(Ford-Fulkerson\) 的操作,每次操作后重新建图。
例题一:网络最大流
思路
版题。
\(Code\)
#include<bits/stdc++.h>
using namespace std;
int n, m, s, t;
int x, y, z;
int head[205], ne[10005], e[10005], idx = 1;
long long val[10005];
int depth[205], q[205];
long long ans;
template<typename T>
inline void read(T&x){
x = 0; char q; bool f = 1;
while(!isdigit(q = getchar())) if(q == '-') f = 0;
while(isdigit(q)){
x = (x<<1) + (x<<3) + (q^48);
q = getchar();
}
x = f?x:-x;
}
template<typename T>
inline void write(T x){
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9) write(x/10);
putchar(x%10^48);
}
inline void add(int u, int v, int w){
e[++idx] = v, val[idx] = w, ne[idx] = head[u], head[u] = idx;
}
inline bool bfs(){
memset(depth, 0, sizeof(depth));
int l, r;
l = r = depth[s] = 1;
q[1] = s;
while(l <= r){
int u = q[l];
++l;
for(register int i = head[u]; i; i = ne[i]){
int v = e[i];
if(depth[v] || !val[i]) continue;
q[++r] = v;
depth[v] = depth[u]+1;
}
}
return depth[t];
}
inline long long dfs(int u, long long in){
if(u == t) return in;
long long out = 0;
for(register int i = head[u]; i; i = ne[i]){
int v = e[i];
if(!val[i] || depth[v] != depth[u]+1) continue;
long long res = dfs(v, min(in, val[i]));
val[i] -= res;
val[i^1] += res;
in -= res;
out += res;
}
if(!out) depth[u] = 0;
return out;
}
int main(){
read(n), read(m), read(s), read(t);
for(register int i = 1; i <= m; ++i){
read(x), read(y), read(z);
add(x, y, z);
add(y, x, 0);
}
while(bfs()) ans += dfs(s, 1e18);
write(ans);
return 0;
}
例题二:Total Flow S
思路
似乎和例一差不多。
\(Code\)
#include<bits/stdc++.h>
using namespace std;
int n, s, t;
char x, y;
int z;
int head[105], ne[2005], e[2005], idx = 1;
long long val[2005];
int depth[105], q[105];
long long ans = 0;
template<typename T>
inline void read(T&x){
x = 0; char q; bool f = 1;
while(!isdigit(q = getchar())) if(q == '-') f = 0;
while(isdigit(q)){
x = (x<<1) + (x<<3) + (q^48);
q = getchar();
}
x = f?x:-x;
}
template<typename T>
inline void write(T x){
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9) write(x/10);
putchar(x%10^48);
}
inline void add(int u, int v, int w){
e[++idx] = v, val[idx] = w, ne[idx] = head[u], head[u] = idx;
}
inline bool bfs(){
memset(depth, 0, sizeof(depth));
int l, r;
q[1] = s;
l = r = depth[s] = 1;
while(l <= r){
int u = q[l++];
for(register int i = head[u]; i; i = ne[i]){
int v = e[i];
if(depth[v] || !val[i]) continue;
depth[v] = depth[u]+1;
q[++r] = v;
}
}
return depth[t];
}
inline long long dfs(int u, long long in){
if(u == t) return in;
long long out = 0;
for(register int i = head[u]; i; i = ne[i]){
int v = e[i];
if(depth[v] != depth[u]+1 || !val[i]) continue;
long long res = dfs(v, min(in, val[i]));
val[i] -= res;
val[i^1] += res;
in -= res;
out += res;
}
if(!out) depth[u] = 0;
return out;
}
int main(){
read(n);
s = 1, t = 26;
for(register int i = 1; i <= n; ++i){
cin >> x >> y;
read(z);
x -= 64, y -= 64;
add(x, y, z);
add(y, x, 0);
}
while(bfs()) ans += dfs(s, 1e18);
write(ans);
return 0;
}