zoukankan      html  css  js  c++  java
  • 网络流小结

    这两天复习了下网络流,高中学的ISAP忘得七七八八,干脆把Dinic,ISAP和预流推进都重新看了一遍,写了个简洁的小结(基本上就是给自己看的)

     

    网络流

    剩余图

    顶点的层次:源点到点的最短路径长度

    层次图建立在剩余图基础上

    阻塞流:不存在增广路时

     

    FF

    复杂度O(n*m*u)

    容量网络、流量网络、残量网络

    用最大流最小割定理证明

     

    EK

    复杂度O(n*m*m)

    建反向边,每次bfs找最短增广路

    最多增广n*m次(每阶段最多增广m次)

     

    Dinic

    多路增广

    1.初始化容量网络和网络流

    2.构造残留网络和层次网络,汇点不在则退出

    3.一次DFS以增广

    4.转2

     

    比起EK单阶段增广从m*m优化为n*m

     

    最高标号预流推进(HLPP)

    预流推进:

    定义盈余、活跃节点、h函数、可推流边(h(u)=h(v)+1)

    1.令flow(s,v)=cap(s,v),flow(u,v)=0,构造h函数,h(s)=n

    2.不存在活顶点则exit

    3.选取活顶点v,选可推流边,没有了则令h(v)=min{h(w)+1},再加入队列

    FIFO队列n*n*m

    先进先出则变为最高标号预流推进,n*n*sqrt(m)

    流量一次性从源中出来,推入汇或最终退回源

     

    ISAP

    Improved Shortest Augmenting Path

    在EK算法基础上,增广后继续增广,直到遇到死路,执行retreat操作(修改d值,重建层次网络)

    retreat时d[u]=min{d[v]+1}(u,v是残量网络邻接点,v靠t更近)(保证了最短路),若无邻接点,取d[u]大于等于n

     

    实现:

    1.初始化d数组,从t到s逆向进行

    2.维护当前节点u

    3.不连通时d[s]>=n

    4.GAP 优化(重要):retreat时若u是唯一一个和t距离d[u]的点,则exit

    5.另一优化:记录上次处理到的邻接边

     

    拿poj1273写了Dinic和ISAP的模板(基本上去掉main就是模板内容)。虽然A了,但可能还有错误,以后做网络流的有发现时候再更正,有空再写个预流推进。

    当前ISAP的模板是递归的,以后再多写几个版本出来。

     

    Dinic

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define rep(i,a,b) for (int i=a;i<=b;++i)
    #define tra(k,u) for (int k=head[u];k!=-1;k=ed[k].next)
    
    const int MAXN=2000;
    const int MAXM=2000;
    const int INF=1e9;
    
    struct edge{
        int to,f,next;
    }ed[2*MAXM+10];
    int head[MAXN],tot;
    int d[MAXN];
    int q[MAXN];
    
    int n,m,s,e,c,ans;
    
    void init(int point_num)
    {
        tot=-1;
        memset(head,-1,sizeof(int)*(point_num+1));
    }
    
    void add_edge(int u,int v,int f)
    {
        ed[++tot].to=v;ed[tot].f=f;ed[tot].next=head[u];head[u]=tot;
        ed[++tot].to=u;ed[tot].f=0;ed[tot].next=head[v];head[v]=tot;
    }
    
    void bfs(int src)
    {
        int l=0,r=0,now;
        q[++r]=src;d[src]=0;
        while (l<r)
        {
            now=q[++l];
            tra(k,now) if (ed[k].f && d[ed[k].to]==-1)
            {
                d[ed[k].to]=d[now]+1;
                q[++r]=ed[k].to;
            }
        }
    }
    
    int dfs(int now,int delta,int t)
    {
    
        if (now==t) return delta;
        int tempflow=0,stream=0;
        tra(k,now) if (ed[k].f && d[ed[k].to]==d[now]+1)
        {
            stream=dfs(ed[k].to,min(delta,ed[k].f),t);
            tempflow+=stream;
            ed[k].f-=stream;
            ed[k^1].f+=stream;
            delta-=stream;
            if (delta==0) break;
        }
        return tempflow;
    }
    
    int maxflow_Dinic(int s,int t,int point_num)
    {
        int maxflow=0;
        while (1)
        {
            memset(d,-1,sizeof(int)*(point_num+1));
            bfs(s);
            if (d[t]==-1) return maxflow;
            maxflow+=dfs(s,INF,t);
        }
    }
    
    int main()
    {
        while(~scanf("%d%d",&n,&m))
        {
            init(m);
            rep(i,1,n)
            {
                scanf("%d%d%d",&s,&e,&c);
                add_edge(s,e,c);
            }
            ans=maxflow_Dinic(1,m,m);
            printf("%d
    ",ans);
        }
    }

    递归ISAP

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define rep(i,a,b) for (int i=a;i<=b;++i)
    #define tra(k,u) for (int k=head[u];k!=-1;k=ed[k].next)
    
    const int MAXN=2000;
    const int MAXM=2000;
    const int INF=1e9;
    
    struct edge{
        int to,f,next;
    }ed[2*MAXM+10];
    int head[MAXN],tot;
    int d[MAXN];
    int q[MAXN];
    int pre[MAXN]; //增广路上的上一个点
    int gap[MAXN]; //gap优化
    
    int n,m,s,e,c,ans;
    
    void init(int point_num)
    {
        tot=-1;
        memset(head,-1,sizeof(int)*(point_num+1));
    }
    
    void add_edge(int u,int v,int f)
    {
        ed[++tot].to=v;ed[tot].f=f;ed[tot].next=head[u];head[u]=tot;
        ed[++tot].to=u;ed[tot].f=0;ed[tot].next=head[v];head[v]=tot;
    }
    
    void bfs(int t)
    {
        int l=0,r=0,now;
        q[++r]=t;d[t]=0;
        while (l<r)
        {
            now=q[++l];
            tra(k,now) if (ed[k^1].f && d[ed[k].to]==-1)
            {
                d[ed[k].to]=d[now]+1;
                q[++r]=ed[k].to;
            }
        }
    }
    
    int dfs(int now,int delta,int t,int point_num)
    {
        if (now==t) return delta;
        int stream=0,tempflow=0,mind=point_num;
        tra(k,now)
        {
            if (ed[k].f)
            {
                if (d[ed[k].to]+1==d[now])
                {
                    stream=dfs(ed[k].to,min(delta,ed[k].f),t,point_num);
                    tempflow+=stream;
                    ed[k].f-=stream;
                    ed[k^1].f+=stream;
                    delta-=stream;
                    if (d[s]>=point_num) return tempflow;
                    if (delta==0) break;
                }
                mind=min(mind,d[ed[k].to]+1);
            }
        }
    
        if (tempflow==0)
        {
            --gap[d[now]];
            if (gap[d[now]]==0) d[s]=point_num;
            d[now]=mind;
            ++gap[d[now]];
        }
    
        return tempflow;
    }
    
    int maxflow_ISAP(int s,int t,int point_num)
    {
        int u=0,ans=0;
        memset(d,-1,sizeof(int)*(point_num+1));
        memset(gap,0,sizeof(int)*(point_num+1));
        bfs(t);                             //bfs可去掉,效率稍微降低
        rep(i,1,n) ++gap[d[i]];
        while (d[s]<point_num)
        {
            ans+=dfs(s,INF,t,point_num);
        }
        return ans;
    }
    
    int main()
    {
        while(~scanf("%d%d",&n,&m))
        {
            init(m);
            rep(i,1,n)
            {
                scanf("%d%d%d",&s,&e,&c);
                add_edge(s,e,c);
            }
            ans=maxflow_ISAP(1,m,m);
            printf("%d
    ",ans);
        }
    }
  • 相关阅读:
    android如何隐藏通知栏和禁止横屏竖屏切换
    android webview加载网页,文字listview和image混合listview的实现
    PHP加密3DES报错 Call to undefined function: mcrypt_module_open() 的解决方法
    http和HTTPS的区别及SSL介绍
    android SQLite数据库 一次性存储多条数据
    两个android程序间的相互调用(apk互调)
    android在学习——activity关闭和dialog.dismiss冲突的解决(Activity has leaked window com.android.internal.policy.impl.PhoneWindow)
    【android】解决因为图片太大引起的内存不足问题,Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
    android数据库操作 sqlite returned: error code = 14, msg = cannot open file at source line 25502
    android实现对SQLite数据库的增、删、改、查
  • 原文地址:https://www.cnblogs.com/terra/p/6986732.html
Copyright © 2011-2022 走看看