【模板】Dinic求网络最大流

来源:互联网 发布:怎么查看网页源码 编辑:程序博客网 时间:2024/06/06 00:20

Dinic算法思路

  1. 根据残量网络计算层次图
  2. 在层次图中使用DFS进行增广直到不存在增广路
  3. 重复以上步骤直到无法增广

首先对每条弧存一条反向弧,初始流量为0,当正向弧剩余流量减少时,反向弧剩余流量随之增加,这样就为每条弧提供了一个反悔的机会,可以让一个流沿反向弧退回而去寻找更优的路线。对于一个网络流图,用bfs将图分层,只保留每个点到下一个层次的弧,目的是减少寻找增广路的代价。对于每一次可行的增广操作,用dfs的方法寻找一条由源点到汇点的路径并获得这条路径的流量c。根据这条路径修改整个图,将所经之处正向边流量减少c,反向边流量增加c。如此反复直到bfs找不到可行的增广路线。

当前弧优化

对于一个节点x,当它在dfs中走到了第i条弧时,前i-1条弧到汇点的流一定已经被流满而没有可行的路线了。那么当下一次再访问x节点的时候,前i-1条弧就可以被删掉而没有任何意义了。所以我们可以在每次枚举节点x所连的弧时,改变枚举的起点,这样就可以删除起点以前的所有弧以达到优化的效果。

【模板】网络最大流 洛谷P3376

#include<bits/stdc++.h>#define INF 10000000using namespace std;int head[10005],nex[200005],tail[200005],cap[200005],tp=-1,dep[10005];int fir[10005];int n,m,s,t,a,b,v;int dfs(int x,int now){    if(!now || x==t)    return now;    int c=0;    for(int &i=fir[x];i!=-1;i=nex[i])    {        if(cap[i] && dep[tail[i]]==dep[x]+1)        {            int f=dfs(tail[i],min(now,cap[i]));            c+=f;            now-=f;            cap[i]-=f;            cap[i^1]+=f;            if(!now)        break;        }    }    return c;}inline bool bfs(){    memset(dep,0,sizeof(dep));    dep[s]=1;    queue<int>q;    q.push(s);    while(!q.empty())    {        int x=q.front();        q.pop();        for(int i=head[x];i!=-1;i=nex[i])        {            if(cap[i]&&!dep[tail[i]])            {                dep[tail[i]]=dep[x]+1;                q.push(tail[i]);            }        }    }    return dep[t];}void add(int x,int y,int v){    nex[++tp]=head[x];    head[x]=tp;    tail[tp]=y;    cap[tp]=v;}inline int Dinic(){    int c=0;    while(bfs())    {        for(int i=1;i<=n;++i)        fir[i]=head[i];        c+=dfs(s,INF);    }        return c;}int main(){    memset(head,-1,sizeof(head));    scanf("%d%d%d%d",&n,&m,&s,&t);    for(int i=1;i<=m;++i)    {        scanf("%d%d%d",&a,&b,&v);        add(a,b,v);        add(b,a,0);    }    printf("%d",Dinic());    return 0;}
原创粉丝点击