最大流算法之EK(最短路径增广算法)

这是网络流最基础的部分——求出源点到汇点的最大流(Max-Flow)。
最大流的算法有比较多,本次介绍的是其中复杂度较高,但是比较好写的EK算法。(不涉及分层,纯粹靠BFS找汇点及回溯找最小流量得到最终的答案)

EK算法,全名Edmonds-Karp算法(最短路径增广算法)。

首先简单介绍一下网络流的基本术语
源点:起点。所有流量皆从此点流出。只出不进
汇点:终点。所有流量最后汇集于此。只进不出
流量上限:有向边(u,v)(及弧)允许通过的最大流量
增广路:一条合法的从源点流向汇点的路径
计算最大流就是不停寻找增广路找到最大值的过程。

合法的网络流具有以下性质
1.f(i,j) <= c(i,j);//任意有向边的流量一定小于等于该边的流量限制
2.f(i,j) = -f(j,i);//从i流向j的流量与j流向i的流量互为相反数反向边
3.out(i) = in(i);//除源点、汇点外,任意一点i流入的流量与流出的相等(只是路过

这里写图片描述(截自洛谷)

EK算法思路
1.通过BFS拓展合法节点(每个节点在本次BFS中仅遍历一次),找到汇点,并记录每个节点的前面节点(pre)(若找不到增广路,算法结束)
2.通过BFS的记录,从汇点回溯回源点,记录下每条弧流量的**最小值**minn, ans += minn(否则就会超出某条边的限制流量)
3.将所有经过的边的流量减去minn,反向边加上minn
4.重复上述步骤,直到找不到增广路,算法结束。

朴素版EK
最为简单的写法,通过邻接矩阵存储。
优点:代码简单,一目了然。
缺点:轻易爆内存,(N^2)的空间太大,N >10000基本就废了(MLE)。
源代码:

#include <bits/stdc++.h> 
using namespace std;
#define INF 0x3f3f3f
#define maxn 10005

int n, m, st, en, flow[maxn][maxn], pre[maxn];
int q[maxn], curr_pos, st_pos, end_pos;
bool wh[maxn];
int max_flow;

void Init()//初始化
{
    int i, a, b, c;
    scanf("%d%d%d%d", &n, &m, &st, &en);
    for(i = 0; i != m; ++i)
    {
        scanf("%d%d%d", &a, &b, &c);
        flow[a][b] += c;
    }
    return ;
}

bool Bfs(int st, int en)//广搜找源点
{
    st_pos = -1, end_pos = 0;
    memset(wh, 0, sizeof wh);
    wh[st] = 1;
    q[0] = st;
    while(st_pos != end_pos)
    {
        curr_pos = q[++st_pos];
        for(int i = 1; i != n+1; ++i)
        {
            if(!wh[i] && flow[curr_pos][i] > 0)
            {
                wh[i] = 1;
                pre[i] = curr_pos;
                if(i == en)
                {
                    return true;
                }
                q[++end_pos] = i;
            }
        }
    }
    return false;
} 

int EK(int start_pos, int end_pos)
{
    int i, minn;
    while(Bfs(start_pos, end_pos))//回溯
    {
        minn = INF;

        for(i = end_pos; i != start_pos; i = pre[i])
        {
            minn = min(minn, flow[pre[i]][i]);
        } 

        for(i = end_pos; i != start_pos; i = pre[i])
        {
            flow[pre[i]][i] -= minn;
            flow[i][pre[i]] += minn;
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值