最大流-Dinic算法

来源:互联网 发布:java redis list对象 编辑:程序博客网 时间:2024/05/20 06:29

Dinic算法

EK算法非常简单明了的解释了最大流的求流的过程,但是复杂度较高,所以需要更高级的算法来解决,没错,标题写着呢,Dinic算法。

Dinic算法的过程,只有两个,没错,也只有两个……(EK算法两个步骤:找增广路,对增广路上所有边加流量)

1.刷层次图

Dinic分为两个步骤:1.求层次图。2.求阻塞流。


1.求层次图
顾名思义,层次图是一层一层的,比如:

这里写图片描述
很明显用bfs就可以求出层次图(其实就是算出距离)。

2.求阻塞流

每次如果存在层次图(存在层次图等价于能从s到t),就在层次图中寻找增广路(只有i-1层的点才能到达i层),直到没有增广路为止。所有的这些增广路成为阻塞流。因为同时求很多增广路,所以我们可以用dfs实现。

不过有个当前弧优化:

每次把一个节点的所有能分配的流量都分光后,前面处理过的弧一定都是满载的(就是cap==flow),所以这些弧已经不需要处理,所以可以标一个数组lst[i]表示最后一次节点i处理到的弧。还有,如果当前所有流量已经分配完毕,直接退出,因为没法继续分,也就不会对答案有更多贡献。

模板

BZOJ 3396

本题有权限……不行的话用上面那道。

#include<cstdio>#include<cstring>#include<algorithm>#define maxn 60#define maxe 1405using namespace std;const int INF=(((1<<30)-1)<<1)+1;struct hdata{    int dad,j;    hdata (int dad=0,int j=0):dad(dad),j(j){}}fa[maxn];int e,ans,tot,lnk[maxn],que[maxn],dst[maxn],cap[maxe],son[maxe],nxt[maxe],flow[maxe],lst[maxn];bool vs[maxn];void _add(int x,int y,int z){    son[++tot]=y; cap[tot]=z; flow[tot]=0; nxt[tot]=lnk[x]; lnk[x]=tot;    son[++tot]=x; cap[tot]=0; flow[tot]=0; nxt[tot]=lnk[y]; lnk[y]=tot;}inline void readi(int &x){    x=0; char ch=getchar();    while ('0'>ch||ch>'9') ch=getchar();    while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}}bool _bfs(){    memset(vs,0,sizeof(vs));    int hed=0,til=1; que[1]=1; vs[1]=true; dst[1]=0;    while (hed!=til){        int x=que[++hed];        for (int j=lnk[x];j;j=nxt[j])            if (!vs[son[j]]&&cap[j]>flow[j]){                vs[son[j]]=true; dst[son[j]]=dst[x]+1; que[++til]=son[j];            }    }    return vs[26];}int _dfs(int x,int t,int now){    if (t==x||now==0) return now; int tem=0;    for (int j=lst[x];j;lst[x]=j=nxt[j])        if (dst[x]+1==dst[son[j]]){            int ew=_dfs(son[j],t,min(now,cap[j]-flow[j]));            if (ew){                flow[j]+=ew; flow[j^1]-=ew; tem+=ew; now-=ew;                if (!now) break;            }        }    return tem;}int getF(){    int tem=0;    while (_bfs()){        for (int i=1;i<=52;i++) lst[i]=lnk[i];        tem+=_dfs(1,26,INF);    }    return tem;}int workc(){    char ch=getchar();    while (('a'>ch||ch>'z')&&('A'>ch||ch>'Z')) ch=getchar();    if ('a'<=ch&&ch<='z') return ch-'a'+27;    else return ch-'A'+1;}int main(){    freopen("water.in","r",stdin);    freopen("water.out","w",stdout);    readi(e); tot=1; ans=0;    memset(nxt,0,sizeof(nxt));    memset(lnk,0,sizeof(lnk));    for (int i=1,x,y,z;i<=e;i++){        x=workc(); y=workc(); readi(z); _add(x,y,z);    }    printf("%d\n",getF());    return 0;}
原创粉丝点击