看了几天的网络流的相关的东西,其实是准备复习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;
}