zoukankan      html  css  js  c++  java
  • 浅谈最大流的Dinic算法

    PART 1 什么是网络流

    网络流(network-flows)是一种类比水流的解决问题方法,与线性规划密切相关。网络流的理论和应用在不断发展,出现了具有增益的流、多终端流、多商品流以及网络流的分解与合成等新课题。网络流的应用已遍及通讯、运输、电力、工程规划、任务分派、设备更新以及计算机辅助设计等众多领域。【引自百度百科】

    PART 2 一些概念

    容量网络:设G(V,E),是一个有向网络,在V中指定了一个顶点,称为源点(记为Vs),以及另一个顶点,称为汇点(记为Vt);对于每一条弧<u,v>属于E,对应有一个权值c(u,v)>0,称为弧的容量.通常吧这样的有向网络G称为容量网络.

    弧的流量:通过容量网络G中每条弧<u,v>,上的实际流量(简称流量),记为f(u,v);

    最大流:在容量网络中,满足弧流量限制条件,且满足平衡条件并且具有最大流量的可行流,称为网络最大流,简称最大流.

    增广路:

    设f是一个容量网络G中的一个可行流,P是从Vs到Vt 的一条链,若P满足以下条件:

       a.P中所有前向弧都是非饱和弧,

       b.P中所有后向弧都是非零弧.

    则称P为关于可行流f 的一条增广路.

    沿这增广路改进可行流的操作称为增广.

    残留容量:给定容量网络G(V,E),及可行流f,弧<u,v>上的残留容量记为cl(u,v)=c(u,v)-f(u,v).每条弧上的残留容量表示这条弧上可以增加的流量.因为从顶点u到顶点v的流量减少,等效与从顶点v到顶点u的流量增加,所以每条弧<u,v>上还有一个反方向的残留容量cl(v,u)=-f(u,v).

    残留网络:设有容量网络G(V,E)及其上的网络流f,G关于f的残留网络记为G(V',E').其中G'的顶点集V'和G中顶点集G相同,V'=V.对于G中任何一条弧<u,v>,如果f(u,v)<c(u,v),那么在G'中有一条弧<u,v>属于E',其容量为c'(u,v)=c(u,v)-f(u,v),如果f(u,v)>0,则在G'中有一条弧<v,u>属于E',其容量为c'(v,u)=f(u,v).残留网络也称为剩余网络。

    PART 3 Dinic算法的基本思路:

      1.根据残量网络计算层次图。

      2.在层次图中使用DFS进行增广直到不存在增广路

      3.重复以上步骤直到无法增广

    PART 4 代码简介

      1.用链式前向星存储图

      2.用bfs将图分层

      3.用dfs进行增广

    PART 5 模板洛谷p3376

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<cctype>
    #include<cmath>
    #include<cstdlib>
    #include<queue>
    #include<ctime>
    #include<vector>
    #include<set>
    #include<map>
    #include<stack>
    using namespace std;
    const int inf=1e9+7;
    struct edge{
          int c,to,next;
    }e[210000];
    int head[11000],cnt,level[11000],cur[11000];
    inline void read(int &x){
          int f=1;x=0;
          char s=getchar();
          while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
          while(s>='0'&&s<='9'){x=x*10+(s-'0');s=getchar();}
          x=(f==1?x:-x);
    }
    inline void add(int u,int v,int w){
          e[cnt].to=v;
          e[cnt].c=w;
          e[cnt].next=head[u];
          head[u]=cnt++;
    }
    inline int bfs(int s,int t){
          memset(level,-1,sizeof(level));
          queue<int>q;
          q.push(s);
          level[s]=0;
          while(!q.empty()){
              int u;
              u=q.front();
              q.pop();
            for(int i=head[u];~i;i=e[i].next){
               int v=e[i].to;
               if(level[v]==-1&&e[i].c){
                 level[v]=level[u]+1;
                 if(v==t)return 1;
                 q.push(v);
               }
            }
          }
        return 0;
    }
    inline int dfs(int u,int v,int flow){
          if(u==v)return flow;
          int res=0;
          if(!cur[u])cur[u]=head[u];
          for(int i=cur[u];~i;i=e[i].next){
              cur[u]=i;//当前弧优化
              int j=e[i].to;
              if(level[j]==level[u]+1&&e[i].c){
                  int f=dfs(j,v,min(flow-res,e[i].c));//多路增广优化 
                  res+=f;
                  e[i].c-=f;
                  e[i^1].c+=f;
              }
          }
          if(!res)level[u]=-1;//炸点优化 
          return res;
    }
    int main()
    {     int n,m,i,j,k,u,w,v,s,t,ans=0;
          read(n),read(m),read(s),read(t);
          memset(head,-1,sizeof(head));
          for(i=1;i<=m;i++){
             read(u),read(v),read(w);
             add(u,v,w);
             add(v,u,0);
          }
          while(bfs(s,t)){
            memset(cur,0,sizeof(cur));
            while(int a=dfs(s,t,inf))
              ans+=a;
          }
          printf("%d
    ",ans);
          return 0;
    }
  • 相关阅读:
    0909初识操作系统
    实验四主存空间的分配和回收
    实验一 DOS命令解释程序的编写
    0909关于操作系统
    实验四主存空间的分配和回收
    实验3评价
    实验一 DOS命令解释程序的编写
    实验三、进程调度模拟程序实验
    实验二、作业调度实验
    0909 第一次上机课之《为什么学操作系统?》
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/8420880.html
Copyright © 2011-2022 走看看