码迷,mamicode.com
首页 > 其他好文 > 详细

网络流初步

时间:2019-07-24 09:28:50      阅读:126      评论:0      收藏:0      [点我收藏+]

标签:dfs   ret   for   tle   mem   max   min   nic   分层图   

网络流初步

P.S.

简单的学习了一下,以后方便复习。

相关概念

  • 源点:只有出边没有入边的点。
  • 汇点:只有入边没有出边的点。
  • 容量和流量:每条有向边上有两个量,容量和流量。从i到j的容量通常用c(i,j)表示,流量则通常是f(i,j)。

相关性质

  • 容量限制:f(u,v)≤c(u,v)
  • 反对称性:f(u,v) = - f(v,u)
  • 流量守恒:对于不是源点也不是汇点的任意结点,流入该结点的流量和等于流出该结点的流量和。

最大流

对于一个网络,合法的流中,使每一条边的流量之和最大的流。

EK增广路算法:

该算法的核心在于:

用bfs寻找一条从源点到汇点的增广路,并记录下这条路上最小的剩余容量,作为本条路上本次通过的流量。

然后直到找不到这样的增广路时,就结束算法,此时得到最大流。

但是注意到每次寻找是随机的,这样会对后续造成影响,从而可能得不到真正的最大流。

所以需要给每个流反悔的机会,即“退流”,用于给更好的方案让路。

这可以用建立反向边来实现,当正向边经过一个流时,反向边对应的增加这个流的流量即可。

dinic算法:

该算法是基于对EK的优化,可以发现EK的每次bfs都只寻找到了一条增广路,而同时却可能遍历整个残量网络。

而dinic则是每次遍历完残量网络后,找到了多条增广路,并完成了流量的更新。

核心内容:

首先bfs在原图上建立分层图。然后沿着分层图多路增广即可。

分层图的构造:

IL int bfs() {
    while(!q.empty()) q.pop();
    memset(d,0,sizeof(d));
    d[S]=1,q.push(S);
    while(!q.empty()) {
        RG int i,y,x=q.front(); q.pop();
        for(i=head[x];i;i=e[i].next)
            if(e[i].v&&!d[y=e[i].to]) {
                d[y]=d[x]+1,q.push(y);
                if(y==T) return 1;
            }
    }
    return 0;
}

当前弧优化:

在固定的一张分层图中,到达一个点的路径是固定的。所以在这种情况下到达了一次某个点后,之前走过的这个点的出边

就没有必要再走了,所以直接记录一下这个点下一条该走的出边即可。由于它是对于一张固定的分层图才能这样,所以每

次bfs重建分层图后需要重置该数组。


int dfs(int x,int flow) {
    if(x==T) return flow;
    RG int i,y,k,rest=flow;
    for(i=cur[x];i&&rest;i=e[i].next)
        if(d[y=e[i].to]==d[x]+1&&e[i].v) {
            cur[x]=i; // Here 
            k=dfs(y,min(rest,e[i].v));
            if(!k) d[y]=0;
            rest-=k,e[i].v-=k,e[i^1].v+=k;
        }
    return flow-rest;
}

IL void dinic() {
    RG int i,j,flow,maxflow=0;
    while(bfs()) {
        memcpy(cur,head,sizeof(head)); //reset
        while(flow=dinic(S,inf)) maxflow+=flow;
    }
}

最小割

最大流最小割定理:一个网络最大流量=最小割中边的容量之和。

费用流

注意此处涉及的费用流是先最大流再最小(大)费用的情况。

一般有spfa-EK或spfa-dinic来求解。即把二者的spfa代替掉bfs即可。

比如dinic费用流的分层图构建部分:


IL int spfa() {
    memset(d,0x3f,sizeof(d));
    while(!q.empty()) q.pop();
    d[S]=0,q.push(S);
    while(!q.empty()) {
        RG int i,y,x=q.front();
        in[x]=0,q.pop(); //spfa 可以多次入队!
        for(i=head[x];i;i=e[i].next)
            if(e[i].v&&d[y=e[i].to]>d[x]+e[i].w) {
                d[y]=d[x]+e[i].w;
                if(!in[y]) in[y]=1,q.push(y);
            }
    }
    return d[T]!=inf;
}

the end

这大概就是基础网络流知识了,关于上下界网络流的学习就看这里吧。

网络流初步

标签:dfs   ret   for   tle   mem   max   min   nic   分层图   

原文地址:https://www.cnblogs.com/Bhllx/p/11235607.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!