题目地址:
https://www.luogu.com.cn/problem/P3376
题目描述:
如题,给出一个网络图,以及其源点和汇点,求出其网络最大流。
输入格式:
第一行包含四个正整数
n
,
m
,
s
,
t
n,m,s,t
n,m,s,t,分别表示点的个数、有向边的个数、源点序号、汇点序号。接下来
M
M
M行每行包含三个正整数
u
i
,
v
i
,
w
i
u_i,v_i,w_i
ui,vi,wi,表示第
i
i
i条有向边从
u
i
u_i
ui出发,到达
v
i
v_i
vi,边权为
w
i
w_i
wi(即该边最大流量为
w
i
w_i
wi)。
输出格式:
一行,包含一个正整数,即为该网络的最大流。
数据范围:
对于
30
%
30\%
30%的数据,保证
n
≤
10
n≤10
n≤10,
m
≤
25
m\leq25
m≤25。对于
100
%
100\%
100%的数据,保证
1
≤
n
≤
200
1 \leq n\leq200
1≤n≤200,
1
≤
m
≤
5000
1 \leq m\leq 5000
1≤m≤5000,
0
≤
w
<
2
31
0 \leq w\lt 2^{31}
0≤w<231。
可以用Dinic算法。每次从源点开始用BFS找增广路,并建立分层图;如果找到增广路,则从源点开始DFS增广并累加流量。找不到增广路了则说明此时已经是最大流。代码如下:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 210, M = 10050;
const long INF = 1e8;
int n, m, S, T;
int h[N], e[M], ne[M], idx;
long f[M];
int q[N], d[N], cur[N];
void add(int a, int b, long c) {
e[idx] = b, ne[idx] = h[a], f[idx] = c, h[a] = idx++;
e[idx] = a, ne[idx] = h[b], f[idx] = 0, h[b] = idx++;
}
bool bfs() {
memset(d, -1, sizeof d);
int hh = 0, tt = 0;
q[tt++] = S, d[S] = 0, cur[S] = h[S];
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;
if (v == T) return true;
// 初始化当前弧
cur[v] = h[v];
q[tt++] = v;
}
}
}
return false;
}
long dfs(int u, long limit) {
if (u == T) return limit;
long flow = 0;
for (int i = cur[u]; ~i && flow < limit; i = ne[i]) {
// 更新当前弧
cur[u] = i;
int v = e[i];
if (d[v] == d[u] + 1 && f[i]) {
int t = dfs(v, min(limit - flow, f[i]));
if (!t) d[v] = -1;
// 更新残留网络
f[i] -= t, f[i ^ 1] += t, flow += t;
}
}
return flow;
}
long dinic() {
long r = 0, flow;
while (bfs()) while (flow = dfs(S, INF)) r += flow;
return r;
}
int main() {
scanf("%d%d%d%d", &n, &m, &S, &T);
memset(h, -1, sizeof h);
for (int i = 0; i < m; i++) {
int a, b;
long c;
scanf("%d%d%ld", &a, &b, &c);
add(a, b, c);
}
printf("%ld\n", dinic());
return 0;
}
时间复杂度 O ( n m ) O(nm) O(nm),空间 O ( n ) O(n) O(n)。