网络流学习总结2

孤人 提交于 2019-11-30 13:29:52

昨天写了网络流的EK算法(写得我自己都不太懂),今天再来总结一下另一个网络最大流的算法Dinic

先来介绍一个概念:残量网络。

一个网络中所有剩余容量大于0的边和与这些边相连的节点组成这个网络的残量网络。

我们回忆一下EK算法的过程:

1.在网络中寻找一条剩余容量大于0的边,把它加入到增广路中。

2.依据找到的增广路,更新边的剩余容量和最大流。

所以,我们每次对增广路的搜索,都可能需要对整个残量网络进行遍历,而只找到一条增广路,还可以进一步优化。

在这里,我们提出了节点的层次d[x],它表示从s到x最少需要经过的边数。在残量网络中,满足d[y] = d[x] + 1的所有边(x , y)构成的子图被称为分层图。显然,它是一张有向无环图。

而传说中的Dinic算法就是通过以下两个步骤来求最大流:

1.在残量网络中不断通过BFS构造分层图,直到s不能到达t。

2.在分层图上用DFS求增广路,在回溯时更新剩余容量。

好啦,大体的介绍完了,具体是怎么回事呢??(其实我也不太懂

在BFS时,我们每找到一个节点x,它到s的最少边数d[x]一定已经求得,那么所有以x为起点的边(x , y)(剩余容量大于0)都可以成为分层图中的子图,于是我们把所有与x相连的节点y的d[y](它还没有被赋值)都更新为d[y] = d[x] + 1,因为只需要多走一条边就可以到y了。这样,在BFS结束时,分层图就已经构建出来了。

然后我们在这张分层图上DFS,直到找到汇点t时就回溯,同时更新DFS时经过的每一条边的剩余容量就可以了,最后每次都更新一下最大流maxflow(然后你就AC啦)。时间复杂度比EK快一点,为O(mn^2)其实都是O(能过)

QAQ还是那道题:洛谷P3376模板题

然后我的好看的代码:

#include<bits/stdc++.h>

using namespace std;

const int inf = 1 << 29,N = 10100,M = 100100;
int n,m,s,t,maxflow,tot = 1;
int ver[M*2],edge[M*2],Next[M*2],head[M*2];

void add(int x,int y,int z){
     ver[++tot] = y;edge[tot] = z;Next[tot] = head[x];head[x] = tot;
     ver[++tot] = x;edge[tot] = 0;Next[tot] = head[y];head[y] = tot;//依然要反向建边。 
}
queue<int>q;
int d[N];//d[x]记录s到x要经过的最少边数。 
bool bfs(){
     memset(d,0,sizeof(d));
     while(q.size()) q.pop();
     q.push(s);d[s] = 1;
     while(q.size()){
        int x = q.front();q.pop();
        for(int i = head[x];i;i = Next[i]){
            if(edge[i]){//在残量网络中寻找。 
                int y = ver[i];
                if(d[y]) continue;//如果d[y]有值,说明在x之前已经搜过了,不再搜。 
                d[y] = d[x] + 1;//没搜过就更新d[y]。 
                q.push(y);
                if(y == t) return 1;//如果到达t,说明分层图建完了。 
             }
         }
     }
     return 0;//未到达说明以求得网络最大流。 
}

int dinic(int x,int flow){//x为当前节点,flow为当前流量。 
    if(x == t) return flow;//搜到t,结束并回溯。 
    int rest = flow,k;
    for(int i = head[x];i;i = Next[i]){
        if(edge[i]){//依旧在残量网络中搜索。 
            int y = ver[i];
            if(d[y] == d[x] + 1){//如果是分层图中的点,说明可以有增广路。 
                k = dinic(y,min(rest,edge[i]));//接着搜索y,当前流为rest和edge[i]中更小的。 
                if(!k) d[y] = 0;//如果k==0,说明无法到达 t了,剪枝,从分层图中删去。 
                edge[i] -= k;//回溯时更新。 
                edge[i^1] += k;
                rest -= k;//剩余流减少,因为要返回flow - rest。 
            }
        }
    }
    return flow - rest;
}

int main(){                
    cin>>n>>m;
    cin>>s>>t;
    for(int i = 1;i <= m; i++){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
    }
    int flow = 0;
    while(bfs())
      while((flow = dinic(s,inf))) maxflow += flow;//更新最大流。 
    printf("%d",maxflow);
    return 0;
}

网络瘤太毒了,我真得只是学了一点点皮毛。。。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!