网络流

网络,是指一个有向带权图,并且有两个特别的点——源点与汇点。

对于流 \(f_{u,v}\),满足以下三个条件

  • 容量限制:对于每条边,流量不超过其容量。
  • 斜对称性:每条边与其反边流量之和为 \(0\),即 \(f_{u,v}=-f_{v,u}\)
  • 流守恒性:从源点流出量等于汇点流入量。

最大流

最大流问题是给定一个网络,求源点到汇点的最大流量。

\(Ford-Fulkerson\) 算法

寻找一条最短路,选出整条路径上的最小值 \(x\) 作为流量,把每条边的容量减小 \(x\),并建立反边并加以合并,如此往复。该算法每执行一次就需要 \(m\) 的时间复杂度,最多会执行 \(ans\) 次,所以时间复杂度最坏为 \(ans\times m\)

\(Edmonds-Karp\) 算法

\(Edmonds-Karp\) 算法实质就是对 \(Ford-Fulkerson\) 的优化,将查找可行路径的方法改为了将所有边权视为 \(1\),跑最短路只需要 \(BFS\),于是时间复杂度降为 \(nm^2\)

\(Dinic\) 算法

\(Dinic\) 算法每次将点分为几层,连边时只连跨层的边,执行 \(Ford-Fulkerson\) 的操作,每次操作后重新建图。

例题一:网络最大流

思路

版题。

\(Code\)
#include<bits/stdc++.h>
using namespace std;

int n, m, s, t;
int x, y, z;
int head[205], ne[10005], e[10005], idx = 1;
long long val[10005];
int depth[205], q[205];
long long ans;

template<typename T>
inline void read(T&x){
	x = 0; char q; bool f = 1;
	while(!isdigit(q = getchar()))	if(q == '-')	f = 0;
	while(isdigit(q)){
		x = (x<<1) + (x<<3) + (q^48);
		q = getchar();
	}
	x = f?x:-x;
}

template<typename T>
inline void write(T x){
	if(x < 0){
		putchar('-');
		x = -x;
	}
	if(x > 9)	write(x/10);
	putchar(x%10^48);
}

inline void add(int u, int v, int w){
	e[++idx] = v, val[idx] = w, ne[idx] = head[u], head[u] = idx;
}

inline bool bfs(){
	memset(depth, 0, sizeof(depth));
	int l, r;
	l = r = depth[s] = 1;
	q[1] = s;
	while(l <= r){
		int u = q[l];
		++l;
		for(register int i = head[u]; i; i = ne[i]){
			int v = e[i];
			if(depth[v] || !val[i])	continue;
			q[++r] = v;
			depth[v] = depth[u]+1;
		}
	}
	return depth[t];
}

inline long long dfs(int u, long long in){
	if(u == t)	return in;
	long long out = 0;
	for(register int i = head[u]; i; i = ne[i]){
		int v = e[i];
		if(!val[i] || depth[v] != depth[u]+1)	continue;
		long long res = dfs(v, min(in, val[i]));
		val[i] -= res;
		val[i^1] += res;
		in -= res;
		out += res;
	}
	if(!out)	depth[u] = 0;
	return out;
}

int main(){
	read(n), read(m), read(s), read(t);
	for(register int i = 1; i <= m; ++i){
		read(x), read(y), read(z);
		add(x, y, z);
		add(y, x, 0);
	}
	while(bfs())	ans += dfs(s, 1e18);
	write(ans);
	return 0;
}

例题二:Total Flow S

思路

似乎和例一差不多。

\(Code\)
#include<bits/stdc++.h>
using namespace std;

int n, s, t;
char x, y;
int z;
int head[105], ne[2005], e[2005], idx = 1;
long long val[2005];
int depth[105], q[105];
long long ans = 0;

template<typename T>
inline void read(T&x){
	x = 0; char q; bool f = 1;
	while(!isdigit(q = getchar()))	if(q == '-')	f = 0;
	while(isdigit(q)){
		x = (x<<1) + (x<<3) + (q^48);
		q = getchar();
	}
	x = f?x:-x;
}

template<typename T>
inline void write(T x){
	if(x < 0){
		putchar('-');
		x = -x;
	}
	if(x > 9)	write(x/10);
	putchar(x%10^48);
}

inline void add(int u, int v, int w){
	e[++idx] = v, val[idx] = w, ne[idx] = head[u], head[u] = idx;
}

inline bool bfs(){
	memset(depth, 0, sizeof(depth));
	int l, r;
	q[1] = s;
	l = r = depth[s] = 1;
	while(l <= r){
		int u = q[l++];
		for(register int i = head[u]; i; i = ne[i]){
			int v = e[i];
			if(depth[v] || !val[i])	continue;
			depth[v] = depth[u]+1;
			q[++r] = v;
		}
	}
	return depth[t];
}

inline long long dfs(int u, long long in){
	if(u == t)	return in;
	long long out = 0;
	for(register int i = head[u]; i; i = ne[i]){
		int v = e[i];
		if(depth[v] != depth[u]+1 || !val[i])	continue;
		long long res = dfs(v, min(in, val[i]));
		val[i] -= res;
		val[i^1] += res;
		in -= res;
		out += res;
	}
	if(!out)	depth[u] = 0;
	return out;
}

int main(){
	read(n);
	s = 1, t = 26;
	for(register int i = 1; i <= n; ++i){
		cin >> x >> y;
		read(z);
		x -= 64, y -= 64;
		add(x, y, z);
		add(y, x, 0);
	}
	while(bfs())	ans += dfs(s, 1e18);
	write(ans);
	return 0;
}
posted @ 2024-10-09 18:32  Zzzzzzzm  阅读(14)  评论(0)    收藏  举报