zoukankan      html  css  js  c++  java
  • 传说中效率最高的最大流算法(Dinic) [转]

    转自:http://www.cnblogs.com/zhuangli/archive/2008/09/07/1259527.html#1310894

    呵呵,又从DK那偷代码了,好兴奋哈,以下是这个算法的简单介绍,不过我用它去解决HDU的1532 竟然TLE,郁闷.到时候再继续问问DK吧...so 烦躁.

    哈哈 终于经过大牛的指点 原来本算法是从0开始标号的......

    Dinic是个很神奇的网络流算法。它是一个基于“层次图”的时间效率优先的最大流算法。

    层次图是什么东西呢?层次,其实就是从源点走到那个点的最短路径长度。于是乎,我们得到一个定理:从源点开始,在层次图中沿着边不管怎么走,经过的路径一定是终点在剩余图中的最短路。(摘自WC2007王欣上论文)注意,这里是要按照层次走。

    那么,MPLA(最短路径增值)的一大堆复杂的证明我就略掉了,有兴趣的请自行参阅WC2007王欣上神牛的论文。

    首先我们得知道,Dinic的基本算法步骤是,先算出剩余图,然后用剩余图算层次图,然后在层次图里找增广路。不知道你想到没有,这个层次图找增广路的方法,恰恰就是Ford-Fulkerson类算法的时间耗费最大的地方,就是找一个最短的增广路。所以呢,层次图就相当于是一个已经预处理好的增广路标志图。

    如何实现Dinic呢?

    首先我们必然要判一下有没有能到达终点的路径(判存在增广路与否),在这个过程中我们顺便就把层次图给算出来了(当然不用算完),然后就沿着层次图一层一层地找增广路;找到一条就进行增广(注意在沿着层次图找增广路的时候使用栈的结构,把路径压进栈);增广完了继续找,找不到退栈,然后继续找有没有与这个结点相连的下一层结点,直到栈空。如果用递归实现,这个东西就很好办了,不过我下面提供的程序是用了模拟栈,当然这样就不存在结点数过多爆栈的问题了……不过写起来也麻烦了一些,对于“继续找”这个过程我专门开了一个数组存当前搜索的指针。

    上面拉拉杂杂说了一大堆,实际上在我的理解中,层次图就是一个流从高往低走的过程(这玩意儿有点像预流推进的标号法……我觉得),在一条从高往低的路径中,自然有些地方会有分叉;这就是Dinic模拟栈中退栈的精华。这就把BFS的多次搜索给省略了不说,时间效率比所谓的理论复杂度要高得多。

    这里有必要说到一点,网络流的时间复杂度都是很悲观的,一般情况下绝对没有可能到达那个复杂度的。

    复制代码
    #include<iostream>
    using namespace std;
    const long maxn=300;
    const long maxm=300000;
    const long inf=0x7fffffff;
    struct node
    {
        
    long v,next;
        
    long val;
    }s[maxm
    *2];
    long level[maxn],p[maxn],que[maxn],out[maxn],ind;
    void init()
    {
        ind
    =0;
        memset(p,
    -1,sizeof(p));
    }
    inline 
    void insert(long x,long y,long z)
    {
        s[ind].v
    =y;
        s[ind].val
    =z;
        s[ind].next
    =p[x];
        p[x]
    =ind++;
        s[ind].v
    =x;
        s[ind].val
    =0;
        s[ind].next
    =p[y];
        p[y]
    =ind++;
    }
    inline 
    void insert2(long x,long y,long z)
    {
        s[ind].v
    =y;
        s[ind].val
    =z;
        s[ind].next
    =p[x];
        p[x]
    =ind++;
        s[ind].v
    =x;
        s[ind].val
    =z;
        s[ind].next
    =p[y];
        p[y]
    =ind++;
    }
    long max_flow(long n,long source,long sink)
    {
        long
    ret=0;
        long
     h=0,r=0;
        
    while(1)
        {
            
    long i;
            
    for(i=0;i<n;++i)
                level[i]
    =0;
            h
    =0,r=0;
            level[source]
    =1;
            que[
    0]=source;
            
    while(h<=r)
            {
                
    long t=que[h++];
                
    for(i=p[t];i!=-1;i=s[i].next)
                {
                    
    if(s[i].val&&level[s[i].v]==0)
                    {
                        level[s[i].v]
    =level[t]+1;
                        que[
    ++r]=s[i].v;
                    }
                }
            }
            
    if(level[sink]==0)break;
            
    for(i=0;i<n;++i)out[i]=p[i];
            
    long q=-1;
            
    while(1)
            {
                
    if(q<0)
                {
                    
    long cur=out[source];
                    
    for(;cur!=-1;cur=s[cur].next)
                    {
                        
    if(s[cur].val&&out[s[cur].v]!=-1&&level[s[cur].v]==2)
                        {
                            
    break;
                        }
                    }
                    
    if(cur>=0)
                    {
                        que[
    ++q]=cur;
                        
    out[source]=s[cur].next;
                    }
                    
    else
                    {
                        
    break;
                    }
                }
                
    long u=s[que[q]].v;
                
    if(u==sink)
                {
                    
    long dd=inf;
                    
    long index=-1;
                    
    for(i=0;i<=q;i++)
                    {
                        
    if(dd>s[que[i]].val)
                        {
                            dd
    =s[que[i]].val;
                            index
    =i;
                        }
                    }
                    ret
    +=dd;
                    
    //cout<<ret<<endl;
                    for(i=0;i<=q;i++)
                    {
                        s[que[i]].val
    -=dd;
                        s[que[i]
    ^1].val+=dd;    
                    }
                    
    for(i=0;i<=q;i++)
                    {
                        
    if(s[que[i]].val==0)
                        {
                            q
    =index-1;
                            
    break;
                        }
                    }
                }
                
    else
                {
                    
    long cur=out[u];
                    
    for(;cur!=-1;cur=s[cur].next)
                    {
                        
    if(s[cur].val&&out[s[cur].v]!=-1&&level[u]+1==level[s[cur].v])
                        {
                            
    break;
                        }
                    }
                    
    if(cur!=-1)
                    {
                        que[
    ++q]=cur;
                        
    out[u]=s[cur].next;
                    }
                    
    else
                    {
                        
    out[u]=-1;
                        q
    --;
                    }
                }
            }
        }
        
    return ret;
    }

    long m,n;

    int main()
    {

        
    while(scanf("%ld %ld",&m,&n)!=EOF)
        {
            init();
            
    for(int i=0;i<n;i++)
            {
                
    long from,to,cost;
                scanf(
    "%ld %ld %ld",&from,&to,&cost);
                insert(--from,--to,cost);
            }
            
    long Start,End;
            scanf(
    "%ld %ld",&Start,&End);
            printf(
    "%ld\n",max_flow(n,--Start,--End));
        }
        
    return 0;
    }
    复制代码
  • 相关阅读:
    2018.10.10python homework
    2018.10.10python学习第十六天part3
    2018.10.10python学习第十六天part2
    2018.10.10python学习第十六天part1
    2018.09.28python学习第十三天part3
    2018.09.28python学习第十三天part2
    2018.09.28python学习第十三天part1
    当不搞技术好几年后,又回来了,忽然很亲切
    福大软工 · BETA 版冲刺前准备(团队)
    事后诸葛亮
  • 原文地址:https://www.cnblogs.com/XBWer/p/2644402.html
Copyright © 2011-2022 走看看