C++ 版:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10010, M = 200010, INF = 1e8;
int n, m, S, T;
int h[N], e[M], f[M], ne[M], idx;
int q[N], d[N], nh[N];
inline void add(int a, int b, int c){
e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
bool bfs(){
memset(d, -1, sizeof d);
q[0] = S, d[S] = 0, nh[S] = h[S];
int hh = 0, tt = 1;
while (hh < tt){
int t = q[hh ++];
for (int i = h[t]; ~i; i = ne[i]){
int v = e[i];
if (d[v] == -1 && f[i]){
d[v] = d[t] + 1;
nh[v] = h[v]; // 可以在开头全copy
if (v == T) return true;
q[tt ++] = v;
}
}
}
return false;
}
int find(int u, int limit){
if (u == T) return limit;
int flow = 0;
for (int i = nh[u]; ~i && flow < limit; i = ne[i]){ // 1. nh 优化, 2. 增广最大量优化
nh[u] = i; // nh当前可行弧优化
int v = e[i];
if (d[v] == d[u] + 1 && f[i]){
int t = find(v, min(f[i], limit - flow));
if (t) flow += t, f[i] -= t; //, f[i ^ 1] += t;
else d[v] = -1; // 3. 废点优化
}
}
return flow;
}
int dinic(){
int res = 0, flow;
while( bfs() ) while (flow = find(S, INF)) res += flow;
return res;
}
int main(){
scanf("%d%d%d%d", &n, &m, &S, &T);
memset(h, -1, sizeof h);
while (m -- ){
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c), add(b, a, 0);
}
printf("%d\n", dinic());
return 0;
}
python3 版:
N, M, inf = 10010, 200010, float('inf')
h, e, f, ne, idx = [-1] * N, [0] * M, [0] * M, [0] * M, 0
q, d, nh = [0] * N, [-1] * N, [0] * N # d: dist or level
def add(a, b, c):
global idx
e[idx], f[idx], ne[idx], h[a] = b, c, h[a], idx
idx += 1
def bfs():
""" rebuild nh[] and d[] """
global nh, d
nh = list(h) # nh[S] = h[S]
d = [-1] * N; d[S] = 0
q[0] = S; hh, tt = 0, 1
while hh < tt:
u = q[hh]; hh += 1
i = h[u]
while i != -1:
v = e[i]
if d[v] == -1 and f[i]:
d[v] = d[u] + 1 # nh[v] = h[v]
if v == T: return True # T 也是要标d和cur的
q[tt] = v; tt += 1
i = ne[i]
return False
def find(u, limit):
if u == T: return limit
flow = 0
i = nh[u] # 1. 当前(起始可用)弧优化
while i != -1 and flow < limit: # 2. 最大增广量优化
nh[u] = i # 当前弧优化。 进阶指南似乎放的位置效率比较低
v = e[i]
if d[v] == d[u] + 1 and f[i]: # 标层级
t = find(v, min(f[i], limit - flow)) # 避免无限递归
if t: flow += t; f[i] -= t; # f[i ^ 1] += t
else: d[v] = -1 # 3. 废点优化,本轮bfs里面不再可能是增广路
i = ne[i]
return flow
def dinic():
res = 0
while bfs():
flow = find(S, inf)
while flow:
res += flow
flow = find(S, inf)
return res
n, m, S, T = map(int, input().split())
while m:
a, b, c = map(int, input().split())
add(a, b, c); add(b, a, 0)
m -= 1
print(dinic())
// luogu-judger-enable-o2
#include <bits/stdc++.h>
#define maxn 1300
#define maxm 120010
using namespace std;
struct edge {
int u, v, cap;
} e[maxm];
struct Dinic {
int tp, s, t, dis[maxn], cur[maxn], que[maxn];
vector<edge> e;
vector<int> v[maxn];
void AddEdge(int x, int y, int flw) {
e.push_back(edge{ x, y, flw });
e.push_back(edge{ y, x, 0 });
v[x].push_back(e.size() - 2);
// v[y].push_back(e.size()-1);
}
int bfs() {
memset(dis, 0x3f, sizeof dis);
int l = 1, r = 1;
que[1] = s;
dis[s] = 0;
while (l <= r) {
int p = que[l++], to;
for (int i : v[p])
if (e[i].cap && dis[to = e[i].v] > 1e9)
dis[to] = dis[p] + 1, que[++r] = to;
}
return dis[t] < 1e9;
}
int dfs(int p, int a) {
if (p == t || !a)
return a;
int sf = 0, flw;
for (int &i = cur[p], to; i < (int)v[p].size(); ++i) {
edge &E = e[v[p][i]];
if (dis[to = E.v] == dis[p] + 1 && (flw = dfs(to, min(a, E.cap)))) {
E.cap -= flw;
e[v[p][i] ^ 1].cap += flw;
a -= flw;
sf += flw;
if (!a) // 把此处移到for的判断里会有问题。。。
break;
}
}
return sf;
}
int dinic(int s, int t, int tp = 1) {
this->s = s;
this->t = t;
this->tp = tp;
int flw = 0;
while (bfs()) {
memset(cur, 0, sizeof cur);
flw += dfs(s, INT_MAX);
}
return flw;
}
} sol;
int n, m, i, s, t, ans;
int main() {
scanf("%d%d%d%d", &n, &m, &s, &t);
for (i = 0; i < m; i++) scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].cap);
sort(e, e + m, [](edge a, edge b) { return a.cap > b.cap; });
for (int tp : { 0, 1 })
for (int p = 1 << 30, i = 0; p; p /= 2) {
while (i < m && e[i].cap >= p) {
if (tp)
sol.v[e[i].v].push_back(i * 2 + 1);
else
sol.AddEdge(e[i].u, e[i].v, e[i].cap);
i++;
}
ans += sol.dinic(s, t, tp);
}
printf("%d\n", ans);
return 0;
}
关于最后的
for (int tp : { 0, 1 })
for (int p = 1 << 30, i = 0; p; p /= 2) {
参考 论如何用dinic ac 最大流 加强版 里面的解释:
1. 先不加反向边跑一遍,然后一次性把反向边都加进去,然后再跑一遍
2. 二进制缩放,只跑大于p的边
看起来应该是针对数据的专门的优化