【网络流算法模板】最大流:dinic模板

来源:互联网 发布:企业内部数据共享方案 编辑:程序博客网 时间:2024/06/02 04:41

这里以poj1459为例,模板中运用了 当前弧优化 ,即如果某次搜索中发现某条边不能流通,就把这条边舍去,以免重复搜索浪费时间

对于分层图的解释:引自白书:“每次寻找最短增广路,因为最短增广路长度在增广过程中始终不会变短。我们可以先进行一次宽度优先搜索,然后考虑由近距离点指向远距离点组成分层图,在上面进行深搜寻找最短增广路。如果找不到新的增广路了,说明最短增广路的长度变长了,或者不存在增广路了,于是通过宽搜寻找构成新的分层图。每一步构造分层图复杂度O(E),每一步完成后至少增广路长度至少增加1,且增广路长度不会超过V-1则,最多O(V)步,这样就能保证复杂度小于等于O(E *V *V)”

若想要认真学习该算法,建议看这位dalao的文章:
https://www.cnblogs.com/SYCstudio/p/7260613.html

#include<iostream>#include<algorithm>#include<stdio.h>#include<queue>#include<stdlib.h>using namespace std;int n,ns,nt,m,iter[105],dis[105];int tot,head[105],nex[40005],to[40005],f[40005],ni[40005];queue<int>q;void add(int u,int v,int w)//建图加边,每次建图时,建一条反向弧,并记录某个弧的反向弧编号{    tot++;//建正向弧    to[tot]=v;    f[tot]=w;    nex[tot]=head[u];    head[u]=tot;    tot++;//建反向弧    to[tot]=u;    f[tot]=0;    nex[tot]=head[v];    head[v]=tot;    //互相记录编号    ni[tot]=tot-1;    ni[tot-1]=tot;}void bfs(int s)//bfs对图按照与源点的距离进行分层{    dis[s]=0;    q.push(s);    while(!q.empty())    {        int now=q.front();q.pop();        for (int i=head[now];i!=0;i=nex[i])        {            int v=to[i];            if (dis[v]==-1 && f[i]>0)            {                dis[v]=dis[now]+1;                q.push(v);            }        }    }}int dinic(int x,int t,int tf) //记录本次最多能流多大{    if (x==t) return tf;    for (int i=iter[x];i!=0;i=nex[i])    {        iter[x]=i;//当前弧优化        int v=to[i];        if (dis[v]!=dis[x]+1 || f[i]==0) continue;//不流通的情况就continue        int tmp=dinic(v,t,min(tf,f[i]));//如果可以从这条边拓展下去可以流通        if (tmp>0)        {            f[i]-=tmp;            f[ni[i]]+=tmp;            return tmp;        }    }    return 0;}int max_f(int s,int t)//求最大流{    int ans=0;    while(1)    {        for (int i=0;i<=n+2;i++)//初始化            iter[i]=head[i],dis[i]=-1;        bfs(s);        if (dis[t]==-1) break;//说明已经没有能到达终点的通路        while(1)        {            int tmpf=dinic(s,t,9990000);            if (tmpf<=0) break;            ans+=tmpf;        }    }    return ans;}char p1,p2,p3;int main(){    while(scanf("%d%d%d%d",&n,&ns,&nt,&m)!=EOF)    {        tot=0;        for (int i=0;i<=n+2;i++)            head[i]=0;        for (int i=1,x,y,z;i<=m;i++)        {            cin>>p1>>x>>p2>>y>>p3>>z;            if (x==y) continue;            add(x,y,z);        }        for (int i=1,x,y;i<=ns;i++)        {            cin>>p1>>x>>p2>>y;            add(n+1,x,y);        }        for (int i=1,x,y;i<=nt;i++)        {            cin>>p1>>x>>p2>>y;            add(x,n+2,y);        }        int ans=max_f(n+1,n+2);        printf("%d\n",ans);    }}
原创粉丝点击