网络流之EK算法求最大流

求最大流的算法有很多种,EK算法就是其中较简单的一种,这个算法没有进行太多的优化,时间复杂度是O(nm^2)。

这个算法的核心就是不断去维护残量图。先对原图建一个残量图,初始残量图就是每条边都加一条反向的0权边,之后进行若干次bfs,每次bfs都去寻找一条从起点到终点的通路,找到以后通路上的各边权减去最小边权,同时反向边加上最小边权,这可能使得某些边的权为0,当边权为0说明这条路已经不能再有流量了,也就是条断边。随着bfs次数增多,这个图最终会变得不再连通,此时就得到了答案了,答案就是之前每次找到的最小边权之和。

网络流算法运行时间比较玄学,虽然这个算法的时间复杂度为O(nm^2),但对于n+m处于小于1e4的题目都是可以解决的。

2171. EK求最大流 为例放一个模板:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
using namespace std;

int n, m, s, t, head[1005], cnt, _min[1005], pre[1005];
bool vis[1005]; 
struct edge
{
	int to, next, w;
}e[20005];

void add(int u, int v, int w)
{
	e[cnt].to = v;
	e[cnt].w = w;
	e[cnt].next = head[u];
	head[u] = cnt;
	cnt++;
}

bool bfs()
{
	memset(vis, false, sizeof vis);
	vis[s] = true;
	_min[s] = 0x3f3f3f3f;
	queue<int> q;
	q.push(s);
	while(q.size())
	{
		int now = q.front();
		q.pop();
		if(now == t) return true;
		for(int i = head[now]; ~i; i = e[i].next)
		{
			int to = e[i].to;
			if(e[i].w && !vis[to])
			{
				vis[to] = true;
				_min[to] = min(e[i].w, _min[now]);
				pre[to] = i;//这里要记录上一条边 
				q.push(to);
			}
		}
	}
	return false;
} 

int EK()
{
	int ans = 0;
	while(bfs())//bfs判连通 
	{
		ans += _min[t];
		for(int i = t; i != s; i = e[pre[i]^1].to)
			e[pre[i]].w -= _min[t], e[pre[i]^1].w += _min[t]; 
	}
	return ans;
}

signed main()
{
	scanf("%d%d%d%d", &n, &m, &s, &t);
	memset(head, -1, sizeof head);
	for(int i = 1; i <= m; i++)
	{
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		add(u, v, w), add(v, u, 0);
	}
	cout << EK();
	
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值