一、内容
题目描述
如题,给出一个网络图,以及其源点和汇点,求出其网络最大流。
输入格式
第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。
接下来M行每行包含三个正整数ui、vi、wi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi)
输出格式
一行,包含一个正整数,即为该网络的最大流。
输入 #1
4 5 4 3
4 2 30
4 3 20
2 3 20
2 1 30
1 3 40
输出 #1
50
二、代码
#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
using namespace std;
const int N = 1e4 + 5, M = 2e5 + 5, INF = 0x3f3f3f3f;
struct E {
int v, w, next;
} e[M];
int n, m, len = 1, s, t, u, v, w, h[N], d[N]; //d[N]代表该点层次
void add(int u, int v, int w) {
//正向边2 反向边为3 3^1 = 2 2^1 = 3
e[++len].v = v;
e[len].w = w;
e[len].next = h[u];
h[u] = len;
}
bool bfs() {//在残余网络上构建分成
memset(d, 0, sizeof(d));//所有点的层次为0
queue<int> q;
d[s] = 1;
q.push(s);
while (!q.empty()) {
int u = q.front(); q.pop();
for (int j = h[u]; j; j = e[j].next) {
int v = e[j].v;
if (e[j].w && !d[v]) { //若果还有容量 并且v点是0层
d[v] = d[u] + 1;
q.push(v);
if (v == t) return 1; //代表能到达终点
}
}
}
return 0;
}
int dinic(int u, int flow) {
if (u == t) return flow; //代表这条增广路径流量
int rest = flow, k; //rest代表剩余流量
for (int j = h[u]; j && rest; j = e[j].next) {
int v = e[j].v;
if (e[j].w && d[v] == d[u] + 1) {//从上一层流向下一层
k = dinic(v, min(rest, e[j].w)); //剩余的 和 这条容量 比较
if (!k) d[v] = 0; //去掉增广完毕的点 下次不再流这个点
e[j].w -= k;//容量减少
e[j ^ 1].w += k; //方向边增加相同流量
rest -= k; //剩余流量减少
}
}
return flow - rest; //总共 - 剩余
}
int main() {
scanf("%d%d%d%d", &n, &m, &s, &t);
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
add(u, v, w); add(v, u, 0); //反向边容量为0
}
int ans = 0, flow;
while (bfs()) {
while (flow = dinic(s, INF)) ans += flow;
}
printf("%d", ans);
return 0;
}