网络最大流 Edmons-Karp算法

网络流的一些定义

  • 网络为一个有向图,其中每一条边 ( x , y ) ∈ E (x,y)\in E (x,y)E都有一个权值 c ( x , y ) c(x,y) c(x,y),若 ( x , y ) ∉ E (x,y) \not \in E (x,y)E c ( x , y ) = 0 c(x,y)=0 c(x,y)=0.
    且有两个点 S , T S,T S,T称为源点汇点
  • 定义 f ( x , y ) f(x,y) f(x,y)为该网络的流量函数,那么 f ( x , y ) f(x,y) f(x,y)有以下性质:
    1. f ( x , y ) ≤ c ( x , y ) f(x,y) \leq c(x,y) f(x,y)c(x,y)
    2. f ( x , y ) = − f ( y , x ) f(x,y)=-f(y,x) f(x,y)=f(y,x)
    3. ∀ x ≠ S , x ≠ T , ∑ ( u , x ) ∈ E f ( u , x ) = ∑ ( x , v ) ∈ E f ( x , v ) \forall x \not = S, x \not = T, \sum_{(u,x)\in E }f(u,x)=\sum_{(x,v)\in E}f(x,v) x=S,x=T,(u,x)Ef(u,x)=(x,v)Ef(x,v)
  • 以上三条性质被称为容量限制斜对称容量守恒
  • 定义一条边的剩余容量为 c ( x , y ) − f ( x , y ) c(x,y)-f(x,y) c(x,y)f(x,y)

最大流

对于一张网络,是的 ∑ ( S , v ) ∈ E f ( S , v ) \sum_{(S,v) \in E}f(S,v) (S,v)Ef(S,v)最大的流函数称为该函数的最大流

E-K增广路算法

若一条从源点 S S S到汇点 T T T的路径的剩余容量都大于 0 0 0,则称这条路径为一条增广路。

那么E-K算法的实质是不断找剩余容量最大的增广路,然后更新路径容量(大概就是这样qwq

code

#include <bits/stdc++.h> 

using namespace std; 

const int N = 1e4 + 100; 
const int M = 1e5 + 100; 
const int INF = 0x3f3f3f3f; 

template <typename T> inline void read(T &s) {
	s = 0; T w = 1, ch = getchar(); 
	while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); } 
	while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); } 
	s *= w; 
}

int n, m, s, t, tot = 1, maxflow = 0; 
int lin[N], pre[N], incf[N]; 
bool vis[N]; 
struct edge {
	int next, to, dis; 
}e[M<<1]; 

inline void add(int from, int to, int dis) {
	e[++tot].to = to; e[tot].next = lin[from]; e[tot].dis = dis; lin[from] = tot; 
	e[++tot].to = from; e[tot].next = lin[to]; e[tot].dis = 0; lin[to] = tot; 
}

bool bfs() {
	memset(vis, false, sizeof(vis)); 
	queue<int> q; q.push(s); vis[s] = 1; 
	incf[s] = INF; 
	while (q.size()) {
		int x = q.front(); q.pop(); 
		for (int i = lin[x]; i; i = e[i].next) {
			if (e[i].dis) {
				int y = e[i].to; 
				if (vis[y]) continue; 
				incf[y] = min(incf[x], e[i].dis); 
				pre[y] = i; 
				q.push(y); vis[y] = true; 
				if (y == t) return true; 
			}
		}
	}
	return false; 
}

void update() {
	int x = t; 
	while (x != s) {
		int i = pre[x]; 
		e[i].dis -= incf[t]; 
		e[i ^ 1].dis += incf[t]; 
		x = e[i ^ 1].to; 
	}
	maxflow += incf[t]; 
}

int main() {
	read(n), read(m), read(s), read(t); 
	int u, v, w; 
	for (int i = 1; i <= m; ++i) {
		read(u), read(v), read(w); 
		add(u, v, w); 
	}
	while (bfs()) update(); 
	printf("%d\n", maxflow); 
	return 0; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值