zoukankan      html  css  js  c++  java
  • 【网络流】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;
    }
  • 相关阅读:
    python常用模块②
    python常用模块①
    面向对象相关部分双下划线方法补充
    面向对象进阶 上
    面向对象初识④
    面向对象初识③
    综合架构-负载均衡
    wecent 搭建
    综合架构--存储
    综合架构--备份
  • 原文地址:https://www.cnblogs.com/mudrobot/p/9026934.html
Copyright © 2011-2022 走看看