洛谷 #3376. 网络流模板(EK+Dinic)

11 篇文章 0 订阅
1 篇文章 0 订阅

题意

给你一个网络图,以及源点和汇点,求最大流

题解(EK)

先读入一个有向图,记录源点到每个节点的流量,每个节点的前驱
从汇点倒着用bfs寻找增广路径(1次只找一条),最后算出最大流
话说从源点开始,记录后继也可以

调试记录

读入顺序
因为是单向图,所以判断now和i之间有连接时,只能取e[now][i]
#include <cstdio>
#include <queue>
#define maxn 2005
#define INF 0x3f3f3f3f

using namespace std;

int n, m, S, T, maxflow = 0;
int e[maxn][maxn], flow[maxn], pre[maxn];

int bfs(int s, int t){
	queue <int> q;
	//while (!q.empty()) q.pop();
	for (int i = 1; i <= n; i++) pre[i] = -1;
	pre[s] = 0;
	q.push(s); flow[s] = INF;
	while (!q.empty()){
		int now = q.front(); q.pop();
		for (int i = 1; i <= n; i++)
			if (e[now][i] && pre[i] == -1){
				pre[i] = now;
				q.push(i);
				flow[i] = min(flow[now], e[now][i]);
			}
	} 
	if (pre[t] == -1) return -1;
	else return flow[t];
}

void EK(int s, int t){
	int inc = 0;
	while ((inc = bfs(s, t)) != -1){
		int k = t;
		while (k != s){
			int last = pre[k];
			e[last][k] -= inc;
			e[k][last] += inc;
			k = last; 
		}
		maxflow += inc;
	}
}

int main(){
	scanf("%d%d%d%d", &n, &m, &S, &T);
	
	for (int x, y, z, i = 1; i <= m; i++){
		scanf("%d%d%d", &x, &y, &z);
		e[x][y] += z;
	}
	EK(S, T);
	printf("%d\n", maxflow);
	
	return 0;
}

题解(Dinic)

EK的优化,用bfs预处理分层,用dfs找增广路径

调试记录

开始cnt必须=-1,因为cnt ^ 1即为cnt的反向边
若cnt=0,1^1\(\not\) = 2
#include <cstdio>
#include <queue>
#include <cstring>
#define maxn 1000005
#define INF 0x3f3f3f3f

using namespace std;

struct node{
	int to, next, dis;
}e[maxn];

int n, m, s, t, maxflow = 0, cnt = -1;
int deep[maxn], head[maxn];

void AddEdge(int u, int v, int len){
	e[++cnt] = (node){v, head[u], len};
	head[u] = cnt;
}

bool bfs(){
	queue <int> q; while (!q.empty()) q.pop();
	memset(deep, 0, sizeof deep);
	
	deep[s] = 1; q.push(s);
	
	while (!q.empty()){
		int now = q.front(); q.pop();
		
		for (int i = head[now]; i != -1; i = e[i].next){
			if (!deep[e[i].to] && e[i].dis){
				deep[e[i].to] = deep[now] + 1;
				q.push(e[i].to);
			}
		}
	}
	
	return (deep[t] != 0);
}

int dfs(int cur, int ans){
	if (cur == t) return ans;
	
	int flow;
	for (int i = head[cur]; i != -1; i = e[i].next){
		if (deep[e[i].to] == deep[cur] + 1 && e[i].dis){
			if (flow = dfs(e[i].to, min(ans, e[i].dis))){
				e[i].dis -= flow;
				e[i ^ 1].dis += flow;
				return flow;
			}
		}
	}
	return 0;
}

void Dinic(){
	while (bfs()){
		while (int tmp = dfs(s, INF))
			maxflow += tmp;
	}
}

int main(){
	memset(head, -1, sizeof head);
	scanf("%d%d%d%d", &n, &m, &s, &t);
	
	for (int x, y, z, i = 1; i <= m; i++){
		scanf("%d%d%d", &x, &y, &z);
		AddEdge(x, y, z); AddEdge(y, x, 0);
	}
	Dinic();
	printf("%d\n", maxflow);
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值