最大流模板 Dinic

一、内容

题目描述

如题,给出一个网络图,以及其源点和汇点,求出其网络最大流。
输入格式
 
第一行包含四个正整数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;
} 
发布了414 篇原创文章 · 获赞 380 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_41280600/article/details/104210804