网络流之EK算法

看了几天的网络流的相关的东西,其实是准备复习Dinic算法,但是顺便记录一下EK(以前刚学网络流的时候,直接上去学Dinic,(不知道听哪个大佬说的,网络流允许卡EK,但是绝对不能卡Dinic )EK碰都没碰,Dinic也没搞太明白,也没记录当时的学习过程,现在忘的一干二净,只能一下一下从头再来)。
回到正题:

EK算法

EK,就是在整个网中不断的去找增广路。我们现在就以最大流为例,我们有一个起点S和一个汇点T,那么我们现在还有一些边在S,T之间(借用一张网图)。
在这里插入图片描述
先说一下什么是增广路,若有一条从S出发到T的通路,并且路上所有的边的通量都大于0,那么就是一条S到T的增广路。
增广路上最小的通量就是汇点最后增加的量,就好比一个水管,决定它流量的最大值总是最细的那一段。
我们可以用BFS不断的找增广路,每找到一条增广路,我们要更新经过的所有边的最大流量,(假设现在有一条增广路最大流量为maxflow,那么所走过的边都要减去maxflow,而它的反边都要加上maxflow,因为整个边的流量之和是不会增加的)直到不再有增广路为止。这就是EK算法做网络流的基本过程。

给道入门例题,可以去试试练练手:P2740 [USACO4.2]草地排水Drainage Ditches

AC代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#include<math.h>
#include<bits/stdc++.h>
#include<map>
using namespace std;
#define LL long long
double eps=1e-10;
const LL N=1e5+10;
int n,m;
int vis[300];
int flow[300];
int pre[1005];
int ans=0;
struct zxc
{
    int to,net,w;
} e[1005];
int head[300];
int tot=0;
void add(int u,int v,int w)
{
    e[tot]= {v,head[u],w};
    head[u]=tot++;
    e[tot]= {u,head[v],0};
    head[v]=tot++;
}
int bfs()
{
    queue<int>q;
    memset(vis,0,sizeof(vis));
   flow[1]=0x3f3f3f3f;
    q.push(1);
    vis[1]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u]; i!=-1; i=e[i].net)
        {
            if(e[i].w)
            {
                int y=e[i].to;
                if(vis[y])
                {
                    continue;
                }

                flow[y]=min(flow[u],e[i].w);
                pre[y]=i;
                q.push(y);
                vis[y]=1;
                if(y==m)
                {
                    return 1;
                }
            }
        }
    }
    return 0;
}
void EK()
{
    while(bfs())
    {
        int s=m;
        while(s!=1)
        {
            int k=pre[s];
            //printf("**%d\n",pre[s]);
            e[k].w-=flow[m];
            e[k^1].w+=flow[m];
            s=e[k^1].to;
        }
        ans+=flow[m];
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int x,y,z;
    memset(head,-1,sizeof(head));
    for(int i=1; i<=n; i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
    }
    EK();
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43402296/article/details/106003539