关于网络流的增广路系列算法有很多种,其中dinic和iSap是时间效率和代码复杂度平衡上比较优秀的两种算法,而两种算法在增广时的思路基本一致并且iSap算法具有更优的时间效率和程序竞赛上的应用范围为更广,同时相比于预流推进代码实现更加简单,所以这里我们介绍iSap算法在网络流问题当中的应用。
iSap的思想是基于层数这个特别的关键字来进行操作的,主要过程是每一次之寻找最短增广路,然后每次利用残量网络更新源点的层数,与dinic类似但又有一些不同之处,在dinic中,每次寻找增广路以前都要进行一次Bfs浪费了大量的时间,iSap则只是在当前层数出现断层时才进行更新,并且利用gap优化层数的查询后能够达到更高的时间效率。
/*
ID: weiluoj1
LANG: C++11
TASK: ditch
*/
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1000 + 10;
int n, m;
int dis[maxn], gap[maxn], Cur[maxn];
int C[maxn][maxn], f[maxn], pre[maxn], flow;
void Bfs() {
queue<int> q;
q.push(n);
gap[0] = 1;
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i=1; i<=n; i++)
if(C[i][u] && !dis[i]) {
dis[i] = dis[u] + 1;
gap[dis[i]]++;
q.push(i);
}
}
}
void iSap() {
int S = 1, T = n, u = S, v, i;
gap[0] = T; f[S] = inf;
for(i=1; i<=n; i++) Cur[i] = 1;
while(dis[S] < T) {
for(i=Cur[u]; i<=n; i++)
if(C[u][i] && dis[i]+1 == dis[u]) break;
if(i != n+1) {
Cur[u] = i;
pre[v = i] = u;
if(f[u] < C[u][v]) f[v] = f[u]; else f[v] = C[u][v];
if((u = v) == T) {
do {
C[pre[u]][u] -= f[T];
C[u][pre[u]] += f[T];
u = pre[u];
}while(u != S);
flow += f[T];
}
}else {
if(--gap[dis[u]] == 0) break;
Cur[u] = 1; dis[u] = T;
for(i=1; i<=n; i++)
if(C[u][i] && dis[i]+1 < dis[u]) dis[u] = dis[i]+1;
++gap[dis[u]];
if(u != S) u = pre[u];
}
}
}
int u, v, w;
int main() {
freopen("ditch.in", "r", stdin);
freopen("ditch.out", "w", stdout);
scanf("%d%d", &m, &n);
for(int i=1; i<=m; i++) {
scanf("%d%d%d", &u, &v, &w);
C[u][v] += w;
}
Bfs();
iSap();
cout << flow << endl;
return 0;
}