【网络流】EK算法及其优化

今天上午我仿佛知道了什么叫做网络流,这里推荐一篇博客,大家入门网络流的可以看一下这篇博客,保证一看就懂!

博客链接:
网络流入门

这里有一篇经过我改过的EK带注释代码(博客里也有一样的,只是加了一些注释),大家可以看一下:

//codevs 1993
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int INF=0x7ffffff;

queue <int> q;
int n,m,x,y,s,t,g[201][201],pre[201],flow[201],maxflow; 
//g邻接矩阵存图,pre增广路径中每个点的前驱,flow源点到这个点的流量 (就是増广路(min))! 

inline int bfs(int s,int t)
{
    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 x=q.front();
        q.pop();
        if (x==t) break;
        for (int i=1; i<=n; i++)
          //EK一次只找一个增广路 ,这句话非常的重要啊!!!!!important! very important! very very important!!!
          //不认真看这句话,不要怪下面自己看不懂! 
          if (g[x][i]>0 && pre[i]==-1)//如果当时x到i点有容量,并且i点还没有找到前驱 
          {
            pre[i]=x;
            flow[i]=min(flow[x],g[x][i]);//是不是觉得有一点像SPFA ??? 找最小的増广路 
            q.push(i);
          }
    }
    if (pre[t]==-1) return -1;//死啦! 
    else return flow[t];
}

//increase为增广的流量 
void EK(int s,int t)
{
    int increase=0;
    while ((increase=bfs(s,t))!=-1)//这里的括号加错了!Tle 
    {//迭代 
        int k=t;//k等于终点 
        while (k!=s)//当k不为起点时 
        {
            int last=pre[k];//从后往前找路径
            g[last][k]-=increase;//正着走残量网络要减去增广量 
            g[k][last]+=increase;//反之,反着走要加上增广量 
            k=last;
        }
        maxflow+=increase;//增加増广路 
    }
}

int main()
{
    scanf("%d%d",&m,&n);//m是挖了几条沟,n是有几条汇点 ,最后一个点n也是小溪的编号 
    for (int i=1; i<=m; i++)
    {
        int z;
        scanf("%d%d%d",&x,&y,&z);
        g[x][y]+=z;//此处不可直接输入,要+= ,为什么???????????????important 
    }
    EK(1,n);
    printf("%d",maxflow);
    return 0;
}

下面大家就会发现一个问题,用邻接矩阵存储,是不是也太费空间了,要是题目让你跑一个有10000个点的网络流岂不凉凉!!!

下面就要献上我们改装过的EK算法!(说白了就是Dinic)

#include<bits/stdc++.h>
using namespace std;
struct listx{
    int to,next=0,f;
}edge[200005];
int cnt=0,n,m,s,t;
int head[10005];
int depth[10005];
void update(int num,int flow)
{
    edge[num].f-=flow;
    edge[num+1].f+=flow;
}
void addedge(int u,int v,int w)
{
    cnt++;
    edge[cnt].next=head[u];
    edge[cnt].to=v;
    edge[cnt].f=w;
    head[u]=cnt;
}
bool bfs()
{
    memset(depth,0,sizeof(depth));
    queue<int>que;
    while(!que.empty())
          {
             que.pop();
          }
    que.push(s);
    depth[s]=1;
    while(!que.empty())
          {
              int cur=que.front();
              que.pop();
              if(cur==t)
                 break;
              for(int i=head[cur];i!=0;i=edge[i].next)
                  {
                    listx temp=edge[i];
                    if(depth[temp.to]==0&&temp.f>0)
                       {
                           depth[temp.to]=depth[cur]+1;
                           que.push(temp.to);
                       }
                  }
          } 
    if(depth[t]==0)
       return false;
    return true;          
}
int dfs(int u,int flow)
{
    if(u==t)
       return flow;
    for(int i=head[u];i!=0;i=edge[i].next)
        {
            listx temp=edge[i];
            if(depth[u]+1==depth[temp.to]&&temp.f>0)
               {
                  flow=flow<temp.f?flow:temp.f;
                  int newx=dfs(temp.to,flow);
                  if(newx>0)
                     {
                        update(i,newx);
                        return newx;
                     }
               }
        }
     return 0;   
}
int main()
{
    int ans=0;
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=1;i<=m;i++)
        {
            int a1,b1,c1;
            scanf("%d%d%d",&a1,&b1,&c1);  
            addedge(a1,b1,c1);
            addedge(b1,a1,0);
        }
    while(bfs())
          {
             int k;
             while(k=dfs(s,10000000))
                   {
                      ans+=k;
                   }
          }
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/mudrobot/p/9026934.html