以下为自己理解,各位巨佬权当小说看好啦,若有误请指出,蟹蟹~
水流出于源,聚于汇。想象许多条错综交错的小溪从源头流出,汇聚到另一头的大海中,网络流描述的问题就是,小溪流入的宽度各不相同,换句话说就是分段限流,假设源头流入的水量是无限的,问水源一次无限的水灌入后能有多少汇聚到大海?
灵魂画手登场
如果要手算,肯定从最开始找,每条可能的小溪都尝试一下,最后得出最大的结果。
计算机也是如此,每条可能的小溪被官方的称作“增广路”,网络流最简单的应该就是EK算法,这种算法,就是每次深搜找增广路,加上答案,就是酱紫,然后所谓dinic算法,是用bfs找增广路,加上弧优化、炸点优化等等,就能跑的飞快,据说能跑1e6?
深入的部分就是找到增广路以后,对增广路怎么处理,这里也是最难懂的地方,其实通俗的讲就是找到每条增广路以后,有效的结果就是这条路里最窄的地方了,就是让这条路所有边都减掉最窄的地方,留下的就是残流,可以给别的增广路用到啦~但是吧,增广路的选取肯定先后的结果是不一样的,所以要给计算机一个反悔的机会呀,因为如果不给的话先被选到的地方不一定是最优的啦,所以就要建一条权值为0的反向边咯。
这里贴一发dinic板子。
#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define PI acos(-1)
#define eps 1e-5
#define rint register int
using namespace std;
typedef long long LL;
typedef pair<LL, int> pli;
typedef pair<int, int> pii;
typedef pair<double, int> pdi;
typedef pair<LL, LL> pll;
typedef pair<double, double> pdd;
typedef map<char, int> mci;
typedef map<string, int> msi;
template<class T>
void read(T &res) {
int f = 1; res = 0;
char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
res *= f;
}
const int INF = 2e9;
const int N = 1e4+4;
const int M = 2e5+5;
const LL Mod = 1e9+7;
struct xx {
int next, to, w;
}edge[M];
//记得tot要置为1噢~方便后面计算啦,就不用初始化head数组啦
int tot = 1, head[N];
void Add(int u, int v, int w) {
edge[++tot] = xx {head[u], v, w};
head[u] = tot;
}
int n, m, s, t;
int dep[N];
int bfs() { //找增广路
memset(dep, 0, sizeof dep);
queue<int> q;
while(!q.empty()) q.pop();
q.push(s); dep[s] = 1;
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = head[u], v; i; i = edge[i].next) {
v = edge[i].to;
if(edge[i].w && !dep[v]) {
dep[v] = dep[u] + 1; q.push(v);
}
}
}
return dep[t]; //如果汇点没有被更新到就是0啦~
}
//这里就是深入的部分啦,是对每条增广路的处理
int dfs(int u, int in) {
if(u == t) return in;
int out = 0;
for(int i = head[u], v; i && in; i = edge[i].next) {
v = edge[i].to;
if(dep[v] == dep[u] + 1 && edge[i].w) {
//min过程就是找这条增广路的最窄部分啦
int x = dfs(v, min(in, edge[i].w));
in -= x; edge[i].w -= x;
//反向边啦,i^1是访问反向边啦(tot要初始1噢)
out += x; edge[i^1].w += x;
}
}
if(!out) dep[u] = 0; //强有力的炸点优化
return out;
}
int dinic() {
int res = 0;
while(bfs()) {
res += dfs(s, INF);
}
return res;
}
int main() {
scanf("%d%d%d%d", &n, &m, &s, &t);
for(int i = 0, u, v, w; i < m; ++i) {
scanf("%d%d%d", &u, &v, &w);
Add(u, v, w); Add(v, u, 0);
}
printf("%d\n", dinic());
return 0;
}
最后啦,推荐一下我学网络牛的地方啦~