最大流 dinic算法 模板

dinic算法在EK算法的基础上增加了分层图的概念,根据从s到各个点的最短距离的不同,把整个图分层。寻找的增广路要求满足所有的点分别属于不同的层,且若增广路为 s,P1,P2Pk,t ,点 v 在分层图中的所属的层记为 deepv ,那么应满足 deeppi=deeppi1+1

算法流程

  1. 对网络中的每一条边,将流量设置为0
  2. 对当前残量网络,构建分层图。若 deept=+ ,则退出,输出答案。
  3. 寻找到残量网络中的一条满足分层图限制的可行流
    (即原网络中满足分层图限制的增广路)
  4. 利用寻找到的增广路『增流』 ,重复步骤2

时间复杂度

在普通情况下, DINIC算法时间复杂度为 O(V2E)
在二分图中, DINIC算法时间复杂度为 O(VE)

优化

• 多路增广
每次不是寻找一条增广路,而是在DFS中,只要可以就递归增广下去,实际上形成了一张增广网。
• 当前弧优化
对于每一个点,都记录上一次检查到哪一条边。因为我们每次增广一定是彻底增广(即这条已经被增广过的边已经发挥出了它全部的潜力,不可能再被增广了),下一次就不必再检查它,而直接看第一个未被检查的边。

优化之后渐进时间复杂度没有改变,但是实际上能快不少。

实际写代码的时候要注意,next数组初始值为-1,存储时从0开始存储,这样在后面写反向弧的时候比较方便,直接异或即可。

代码

// codevs 1993
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;

const int max_n=205;
const int max_m=205;
const int max_e=max_m*2;
const int inf=1e9;

int point[max_n],next[max_e],v[max_e],remain[max_e],deep[max_n],cur[max_n];
int n,m,x,y,cap,tot,maxflow;
queue <int> q;

inline void add(int x,int y,int cap){
    ++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=cap;
    ++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0;
}

//分层 
inline bool bfs(int s,int t){
    //初始化 
    memset(deep,0x7f,sizeof(deep));
    deep[s]=0;
    for (int i=1;i<=n;++i)
      cur[i]=point[i];
    while (!q.empty()) q.pop();
    q.push(s);

    while (!q.empty()){
        int now=q.front(); q.pop();
        for (int i=point[now];i!=-1;i=next[i])
          if (deep[v[i]]>inf&&remain[i]){
            deep[v[i]]=deep[now]+1;
            q.push(v[i]);
          }
    }

    return deep[t]<inf;
}

//找到当前点最大能够增广的flow 
//limit表示到目前为止走过的增广路容量最小的边 
inline int dfs(int now,int t,int limit){
    if (!limit||now==t) return limit;
    int flow=0,f;

    for (int i=cur[now];i!=-1;i=next[i]){
        cur[now]=i;
        if (deep[v[i]]==deep[now]+1&&(f=dfs(v[i],t,min(limit,remain[i])))){
            flow+=f;
            limit-=f;
            remain[i]-=f;
            remain[i^1]+=f;
            if (!limit) break;
        }
    }
    return flow;
}

inline void dinic(int s,int t){
    while (bfs(s,t))
      maxflow+=dfs(s,t,inf);
}

int main(){
    tot=-1;
    memset(point,-1,sizeof(point));
    memset(next,-1,sizeof(next));

    scanf("%d%d",&m,&n);
    for (int i=1;i<=m;++i){
        scanf("%d%d%d",&x,&y,&cap);
        add(x,y,cap);
    }

    dinic(1,n);
    printf("%d\n",maxflow);
}

你可能感兴趣的:(网络流)