其他分享
首页 > 其他分享> > 网络最大流三题

网络最大流三题

作者:互联网

昨天杭电多校1001题人均过,该学学网络流了(虽然dls说过,网络流只能出金牌题)

在b站看了电子科大的网络流入门,学会了dinic的板子,还不会严格证明

求单源单汇的最大流,简单来说就是只要残量网络能够到达汇点,就跑一遍增广路,然后再求残量网络,再跑增广路……直到汇点无法到达。
关键点:建反向边,残量网络通过分层图来判断,dinic优化
其中,dinic优化又分为当前弧优化、多路增广和炸点
当前弧优化貌似useless,多路增广就是将当前点能够走通的路全走一遍再返回,炸点就是把没用的点堵塞

最大流三题:

洛谷P3376 【模板】网络最大流
最大流的模板题

#include<bits/stdc++.h>
using namespace std;

#define fr first
#define se second
#define et0 exit(0);
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef unsigned long long ULL;

const int INF = 0X3f3f3f3f, N = 200 + 10, M = 5000 + 10, MOD = 1e9 + 7;
const double eps = 1e-7, pi = acos(-1);

int aim;

int dep[N];

int head[N], idx;

struct EGDE {
	int to, next; 
	LL w;
} eg[M << 1];

void add(int x, int y, int w) {
	eg[idx].to = y;
	eg[idx].next = head[x];
	eg[idx].w = w;
	head[x] = idx++;
}

int bfs(int S, int T) {
	queue<int> Q;
	memset(dep, 0, sizeof dep);
	dep[S] = 1;
	Q.push(S);
	
	while (!Q.empty()) {
		int u = Q.front();
		Q.pop();
		for (int i = head[u]; ~i; i = eg[i].next) {
			int to = eg[i].to;
			if (eg[i].w && !dep[to]) {
				dep[to] = dep[u] + 1;
				Q.push(to);
			}
		}
	}
	
	return dep[T];
}

LL dfs(int u, LL rf) {
	if (u == aim) return rf;
	
	LL uf = 0;
	for (int i = head[u]; ~i; i = eg[i].next) {
		int to = eg[i].to;
		if (eg[i].w && dep[to] == dep[u] + 1) {
			LL tf = dfs(to, min(rf, eg[i].w));
			eg[i].w -= tf, eg[i ^ 1].w += tf;
			rf -= tf, uf += tf;
		}
	}
	
	if (!uf) dep[u] = -2;
	return uf;
}

LL maxflow(int S, int T) {
	LL res = 0;
	aim = T;
	
	while (bfs(S, T)) res += dfs(S, 1ll << 31);
	
	return res;
}

void work() {
	int n, m, s, t;
	memset(head, -1, sizeof head);

	cin >> n >> m >> s >> t;
	rep (i, 1, m) {
		LL u, v, w;
		cin >> u >> v >> w;
		add(u, v, w), add(v, u, 0);
	}
	
	cout << maxflow(s, t) << endl;
}

signed main() {
	IO

	int test = 1;
//	cin >> test;

	while (test--) {
		work();
	}

	return 0;
}

洛谷P1264 K-联赛

这题难就难在建图。
第\(i\)个队伍想要获胜,首先自己的胜场要尽可能多,也就是接下来跟自己有关的比赛全部获胜,设胜场为\(w_i\);
那么剩下的每个队伍胜场都不能超过\(w_i\),从每个队伍\(j\)向\(i\)连一条容量为\(w_i-w_j\)的边;
然后将队伍之间的比赛也当做若干个节点,从源点向比赛连一个边权为比赛数的边,再从比赛向两个队伍分别连边权为比赛数的边;
在边权的容量限制下,可以证明只要最大流为剩余比赛数,就一定有一种合法的比赛方案使第\(i\)队获胜。

#include<bits/stdc++.h>
using namespace std;

#define fr first
#define se second
#define et0 exit(0);
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef unsigned long long ULL;

const int INF = 0X3f3f3f3f, N = 1000 + 10, M = 2000 + 10, MOD = 1e9 + 7;
const double eps = 1e-7, pi = acos(-1);

int n;
int w[N], g[N][N];

int aim;
int dep[N];

int head[N], idx, gdx;

struct EGDE {
	int to, next, w;
} eg[M << 1];

void add(int x, int y, int w) {
	eg[idx].to = y;
	eg[idx].next = head[x];
	eg[idx].w = w;
	head[x] = idx++;
}

int bfs(int S, int T) {
	queue<int> Q;
	memset(dep, 0, sizeof dep);
	dep[S] = 1;
	Q.push(S);
	
	while (!Q.empty()) {
		int u = Q.front();
		Q.pop();
		for (int i = head[u]; ~i; i = eg[i].next) {
			int to = eg[i].to;
			if (eg[i].w && !dep[to]) {
				dep[to] = dep[u] + 1;
				Q.push(to);
			}
		}
	}
	
	return dep[T];
}

int dfs(int u, int rf) {
	if (u == aim) return rf;
	
	int uf = 0;
	for (int i = head[u]; ~i; i = eg[i].next) {
		int to = eg[i].to;
		if (eg[i].w && dep[to] == dep[u] + 1) {
			int tf = dfs(to, min(rf, eg[i].w));
			eg[i].w -= tf, eg[i ^ 1].w += tf;
			rf -= tf, uf += tf;
		}
	}
	
	if (!uf) dep[u] = -2;
	return uf;
}

int maxflow(int S, int T) {
	int res = 0;
	aim = T;
	
	while (bfs(S, T)) res += dfs(S, 1 << 20);
	
	return res;
}

void work() {
	int tmp;
	cin >> n;
	rep (i, 1, n) cin >> w[i] >> tmp;
	rep (i, 1, n) rep (j, 1, n) cin >> g[i][j];
	
	rep (i, 1, n) {
		int sum = 0;
		bool ok = true;
		idx = 0, gdx = n;
		memset(head, -1, sizeof head);
		
		int wi = w[i];
		rep (j, 1, n) wi += g[i][j];
		rep (j, 1, n) {
			if (j == i) continue;
			if (wi < w[j]) {
				ok = false;
				break;
			}
			add(j, i, wi - w[j]), add(i, j, 0);
		}
		rep (j, 1, n) {
			if (j == i) continue;
			rep (k, j + 1, n) {
				if (k == i) continue;
				sum += g[j][k];
				gdx++;
				add(0, gdx, g[j][k]), add(gdx, 0, 0);
				add(gdx, j, g[j][k]), add(j, gdx, 0);
				add(gdx, k, g[j][k]), add(k, gdx, 0);
			}
		}
		if (!ok) continue;
		
		int t = maxflow(0, i); 
		if (t == sum) cout << i << " ";
	}
	cout << endl;
}

signed main() {
	IO
	
	int test = 1;
//	cin >> test;

	while (test--) {
		work();
	}

	return 0;
}

杭电多校第十场 1001 Winner Prediction

跟上题类似,建图方式是一样的

#include<bits/stdc++.h>
using namespace std;

#define fr first
#define se second
#define et0 exit(0);
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef unsigned long long ULL;

const int INF = 0X3f3f3f3f, N = 2000 + 10, M = 5000 + 10, MOD = 1e9 + 7;
const double eps = 1e-7, pi = acos(-1);

int n;
int w[N];

int aim;
int dep[N];

int head[N], idx, gdx;

struct EGDE {
	int to, next, w;
} eg[M << 1];

void add(int x, int y, int w) {
	eg[idx].to = y;
	eg[idx].next = head[x];
	eg[idx].w = w;
	head[x] = idx++;
}

int bfs(int S, int T) {
	queue<int> Q;
	memset(dep, 0, sizeof dep);
	dep[S] = 1;
	Q.push(S);
	
	while (!Q.empty()) {
		int u = Q.front();
		Q.pop();
		for (int i = head[u]; ~i; i = eg[i].next) {
			int to = eg[i].to;
			if (eg[i].w && !dep[to]) {
				dep[to] = dep[u] + 1;
				Q.push(to);
			}
		}
	}
	
	return dep[T];
}

int dfs(int u, int rf) {
	if (u == aim) return rf;
	
	int uf = 0;
	for (int i = head[u]; ~i; i = eg[i].next) {
		int to = eg[i].to;
		if (eg[i].w && dep[to] == dep[u] + 1) {
			int tf = dfs(to, min(rf, eg[i].w));
			eg[i].w -= tf, eg[i ^ 1].w += tf;
			rf -= tf, uf += tf;
		}
	}
	
	if (!uf) dep[u] = -2;
	return uf;
}

int maxflow(int S, int T) {
	int res = 0;
	aim = T;
	
	while (bfs(S, T)) res += dfs(S, 1 << 27);
	
	return res;
}

void work() {
	int sum = 0, m1, m2;
	bool ok = true;
	idx = 0;
	memset(head, -1, sizeof head);

	cin >> n >> m1 >> m2;
	gdx = n;
	
	rep (i, 1, n) w[i] = 0;
	rep (i, 1, m1) {
		int x, y, z;
		cin >> x >> y >> z;
		if (z) w[x]++;
		else w[y]++;
	} 
	rep (i, 1, m2) {
		int x, y;
		cin >> x >> y;
		if (x == 1 || y == 1) w[1]++;
		else {
			sum++;
			gdx++;
			add(0, gdx, 1), add(gdx, 0, 0);
			add(gdx, x, 1), add(x, gdx, 0);
			add(gdx, y, 1), add(y, gdx, 0);	
		}
	}
	
	int w1 = w[1];
	rep (i, 2, n) {
		if (w1 < w[i]) {
			ok = false;
			break;
		}
		add(i, 1, w1 - w[i]), add(1, i, 0);
	}
	if (!ok) {
		cout << "NO" << endl;
		return;
	}
	
	int t = maxflow(0, 1); 
	if (t == sum) cout << "YES" << endl;
	else cout << "NO" << endl;
	
	rep (i, 0, n) w[i] = 0;
}

signed main() {
	IO
	memset(head, -1, sizeof head);
	
	int test = 1;
	cin >> test;

	while (test--) {
		work();
	}

	return 0;
}

标签:最大,gdx,int,eg,网络,dep,add,rep,流三题
来源: https://www.cnblogs.com/xhy666/p/16606940.html