2173. Dinic/ISAP求最小割(最大流,最小割,DinicI/SAP)

活动 - AcWing

给定一个包含 n 个点 m 条边的有向图,并给定每条边的容量,边的容量非负。

图中可能存在重边和自环。求从点 S 到点 T 的最小割。

输入格式

第一行包含四个整数 n,m,S,T。

接下来 m 行,每行三个整数 u,v,c,表示从点 u 到点 v 存在一条有向边,容量为 c。

点的编号从 1 到 n。

输出格式

输出点 S 到点 T 的最小割。

如果从点 S 无法到达点 T 则输出 0。

数据范围

2≤n≤10000,

1≤m≤100000,

0≤c≤10000,

S≠T

输入样例:
复制代码
7 14 1 7
1 2 5
1 3 6
1 4 5
2 3 2
2 5 3
3 2 2
3 4 3
3 5 3
3 6 7
4 6 5
5 6 1
6 5 1
5 7 8
6 7 7
输出样例:
复制代码
14

解析:

基本概念

1.1 流网络,不考虑反向边

1.2 可行流,不考虑反向边

1.2.1 两个条件:容量限制、流量守恒

1.2.2 可行流的流量指从源点流出的流量 - 流入源点的流量

1.2.3 最大流是指最大可行流

1.3 残留网络,考虑反向边,残留网络的可行流f' + 原图的可行流f = 原题的另一个可行流

(1) |f' + f| = |f'| + |f|

(2) |f'| 可能是负数

1.4 增广路径

1.5 割

1.5.1 割的定义

1.5.2 割的容量,不考虑反向边,"最小割"是指容量最小的割。

1.5.3 割的流量,考虑反向边,f(S, T) <= c(S, T)

1.5.4 对于任意可行流f,任意割[S, T],|f| = f(S, T)

1.5.5 对于任意可行流f,任意割[S, T],|f| <= c(S, T)

1.5.6 最大流最小割定理

(1) 可以流f是最大流

(2) 可行流f的残留网络中不存在增广路

(3) 存在某个割[S, T],|f| = c(S, T)

1.6. 算法

1.6.1 EK O(nm^2)

1.6.2 Dinic O(n^2m)

1.7 应用

1.7.1 二分图

(1) 二分图匹配

(2) 二分图多重匹配

1.7.2 上下界网络流

(1) 无源汇上下界可行流

(2) 有源汇上下界最大流

(3) 有源汇上下界最小流

1.7.3 多源汇最大流

作者:yxc

链接:https://www.acwing.com/activity/content/code/content/424558/

来源:AcWing

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

有最大流最小割定理知:最大流等于最小割

cpp 复制代码
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>
#include<sstream>
#include<deque>
#include<unordered_map>
#include<unordered_set>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int N = 1e4+5, M = 1e5 * 2 + 10, INF = 0x3f3f3f3f;
int n, m, S, T;
int h[N], e[M], f[M], ne[M], idx;
int q[N], d[N], cur[N];

void add(int a, int b, int c) {
	e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx++;
	e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx++;
}

bool bfs() {
	int hh = 0, tt = 0;
	memset(d, -1, sizeof d);
	q[0] = S, d[S] = 0, cur[S] = h[S];
	while (hh <= tt) {
		int t = q[hh++];
		for (int i = h[t]; i != -1; i = ne[i]) {
			int j = e[i];
			if (d[j] == -1 && f[i]) {
				d[j] = d[t] + 1;
				cur[j] = h[j];
				if (j == T)return 1;
				q[++tt] = j;
			}
		}
	}
	return 0;
}

int find(int u, int limit) {
	if (u == T)return limit;
	int flow = 0;
	for (int i = cur[u]; i != -1 && flow < limit; i = ne[i]) {
		int j = e[i];
		cur[u] = i;
		if (d[j] == d[u] + 1 && f[i]) {
			int t = find(j, min(f[i], limit - flow));
			if (!t)d[j] = -1;
			f[i] -= t, f[i ^ 1] += t, flow += t;
		}
	}
	return flow;
}

int dinic() {
	int ret = 0, flow;
	while (bfs())while (flow = find(S, INF))ret += flow;
	return ret;
}

int main() {
	cin >> n >> m >> S >> T;
	memset(h, -1, sizeof h);
	for (int i = 1,a,b,c; i <= m; i++) {
		scanf("%d%d%d", &a, &b, &c);
		add(a, b, c);
	}
	printf("%d\n", dinic());
	return 0;
}
相关推荐
是苏浙几秒前
零基础入门C语言之C语言实现数据结构之单链表经典算法
c语言·开发语言·数据结构·算法
橘颂TA8 分钟前
【剑斩OFFER】算法的暴力美学——点名
数据结构·算法·leetcode·c/c++
迷途之人不知返1 小时前
数据结构之,栈与队列
数据结构
MATLAB代码顾问1 小时前
多种时间序列预测算法的MATLAB实现
开发语言·算法·matlab
高山上有一只小老虎3 小时前
字符串字符匹配
java·算法
愚润求学3 小时前
【动态规划】专题完结,题单汇总
算法·leetcode·动态规划
MOONICK3 小时前
数据结构——哈希表
数据结构·哈希算法·散列表
林太白3 小时前
跟着TRAE SOLO学习两大搜索
前端·算法
ghie90904 小时前
图像去雾算法详解与MATLAB实现
开发语言·算法·matlab
云泽8084 小时前
从三路快排到内省排序:探索工业级排序算法的演进
算法·排序算法