网络流

· · 个人记录

浅谈网络流的各种建模方法

最大流

由于其他算法并不常用,所以这里只给出 \text{Dinic} 的用法。

Dinic

常量与变量

函数

代码

struct Dinic{
    const ll INF=0x3f3f3f3f3f3f3f3f;
    int head[N],ver[M<<1],nxt[M<<1],tot=1;
    ll edge[M<<1];
    void add(int x,int y,ll z){
        ver[++tot]=y,edge[tot]=z,nxt[tot]=head[x],head[x]=tot;
        ver[++tot]=x,edge[tot]=0,nxt[tot]=head[y],head[y]=tot;
    }
    ll maxflow;
    int S,T,d[N],now[N];
    queue<int>q;
    bool bfs(){
        memset(d,0,sizeof(d));
        while(q.size())q.pop();
        q.push(S);d[S]=1;now[S]=head[S];
        while(q.size()){
            int x=q.front();q.pop();
            for(int i=head[x],y;i;i=nxt[i]){
                y=ver[i];
                if(edge[i]&&!d[y]){
                    q.push(y);now[y]=head[y];
                    d[y]=d[x]+1;
                    if(y==T)return 1;
                }
            }
        }
        return 0;
    }
    ll dinic(int x,ll flow){
        if(x==T)return flow;
        ll rest=flow;
        for(int i=now[x],k,y;i&&rest;i=nxt[i]){
            y=ver[i];now[x]=i;
            if(edge[i]&&d[y]==d[x]+1){
                k=dinic(y,min(rest,edge[i]));
                if(!k)d[y]=0;
                edge[i]-=k;edge[i^1]+=k;
                rest-=k;
            }
        }
        return flow-rest;
    }
    void solve(){
        ll flow=maxflow=0;
        while(bfs())while(flow=dinic(S,INF))maxflow+=flow;
    }
}mf;

Edmonds-Karp 动能算法

代码

const ll INF=1ll<<60;
int n,m,s,t,pre[N];
int head[N],nxt[M<<1],ver[M<<1],tot=1;
ll incf[N],edge[M<<1],maxflow=0;
bool v[N];
void add(int x,int y,ll z){
    ver[++tot]=y,edge[tot]=z,nxt[tot]=head[x],head[x]=tot;
    ver[++tot]=x,edge[tot]=0,nxt[tot]=head[y],head[y]=tot;
}
bool fk_bfs(){
    memset(v,0,sizeof(v));
    queue<int>q;
    q.push(s);
    v[s]=1;
    incf[s]=INF;
    while(q.size()){
        int x=q.front();
        q.pop();
        for(int i=head[x];i;i=nxt[i])
            if(edge[i]){
                int y=ver[i];
                if(v[y])
                    continue;
                incf[y]=min(incf[x],edge[i]);
                pre[y]=i;
                v[y]=1;
                q.push(y);
                if(y==t)
                    return 1;
            }
    }
    return 0;
}
void update(){
    int x=t;
    while(x!=s){
        int i=pre[x];
        edge[i]-=incf[t];
        edge[i^1]+=incf[t];
        x=ver[i^1];
    }
    maxflow+=incf[t];
}
void fk(){
    while(fk_bfs())
        update();
}

Highest Label Preflow Push 最高标号预流推进算法

代码

int n,m,s,t;
int head[N],nxt[M<<1],ver[M<<1],edge[M<<1],tot=1;
int cnt=1,h[N],rest[N],gap[N],hest=0;
stack<int>B[N];
void add(int x,int y,ll z){
    ver[++tot]=y,edge[tot]=z,nxt[tot]=head[x],head[x]=tot;
    ver[++tot]=x,edge[tot]=0,nxt[tot]=head[y],head[y]=tot;
}
int push(int x){
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i],z=edge[i];
        if(z&&(x==s||h[x]==h[y]+1)){
            int k=(x==s)?z:min(z,rest[x]);
            if(y!=s&&y!=t&&!rest[y]){
                B[h[y]].push(y);
                hest=max(hest,h[y]);
            }
            rest[x]-=k;
            rest[y]+=k;
            edge[i]-=k;
            edge[i^1]+=k;
            if(!rest[x])
                return 0;
        }
    }
    return 1;
}
void relabel(int x){
    h[x]=h[0];
    for(int i=head[x];i;i=nxt[i])
        if(edge[i])
            h[x]=min(h[x],h[ver[i]]);
    if(++h[x]<n){
        B[h[x]].push(x);
        hest=max(hest,h[x]);
        gap[h[x]]++;
    }
}
bool bfs(){
    memset(h,0x3f,sizeof(h));
    queue<int>q;
    q.push(t);
    h[t]=0;
    while(q.size()){
        int x=q.front();
        q.pop();
        for(int i=head[x];i;i=nxt[i])
            if(edge[i^1]&&h[ver[i]]>h[x]+1){
                h[ver[i]]=h[x]+1;
                q.push(ver[i]);
            }
    }
    return h[s]!=h[0];
}
int select(){
    while(!B[hest].size()&&hest>=0)
        hest--;
    return hest==-1?0:B[hest].top();
}
int hlpp(){
    if(!bfs())
        return 0;
    memset(gap,0,sizeof(gap));
    for(int i=1;i<=n;i++)
        if(h[i]!=h[0])
            gap[h[i]]++;
    h[s]=n;
    push(s);
    int x;
    while(x=select()){
        B[hest].pop();
        if(push(x)){
            if(!(--gap[h[x]]))
                for(int i=1;i<=n;i++)
                    if(i!=s&&i!=t&&h[i]>h[x]&&h[i]<n+1)
                        h[i]=n+1;
            relabel(x);
        }
    }
    return rest[t];
}

最小费用最大流

SSP 算法

常量与变量

函数

代码

struct Dinic{
    const ll INF=0x3f3f3f3f3f3f3f3f;
    int head[N],ver[M<<1],nxt[M<<1],tot=1;
    ll edge[M<<1],cost[M<<1],dis[N],mxflow,micost;
    void add(int x,int y,ll z,ll w){
        ver[++tot]=y,edge[tot]=z,cost[tot]=w,nxt[tot]=head[x],head[x]=tot;
        ver[++tot]=x,edge[tot]=0,cost[tot]=-w,nxt[tot]=head[y],head[y]=tot;
    }
    queue<int>q;
    int v[N],now[N],d[N],S,T;
    bool spfa(){
        memset(dis,0x3f,sizeof(dis));
        memset(v,0,sizeof(v));
        while(q.size())q.pop();
        q.push(S);dis[S]=0;d[S]=v[S]=1;now[S]=head[S];
        while(q.size()){
            int x=q.front();q.pop();
            v[x]=0;
            for(int i=head[x],y;i;i=nxt[i]){
                y=ver[i];
                if(edge[i]&&dis[y]>dis[x]+cost[i]){
                    dis[y]=dis[x]+cost[i];
                    d[y]=d[x]+1;
                    if(!v[y]){
                        q.push(y);
                        v[y]=1;now[y]=head[y];
                    }
                }
            }
        }
        return dis[T]!=INF;
    }
    ll dinic(int x,ll flow){
        if(x==T)return flow;
        ll rest=flow,k;
        for(int i=now[x],y;i&&rest;i=nxt[i]){
            y=ver[i];now[x]=i;
            if(edge[i]&&dis[y]==dis[x]+cost[i]&&d[y]==d[x]+1){
                k=dinic(y,min(edge[i],rest));
                if(!k)d[y]=0;
                edge[i]-=k;edge[i^1]+=k;
                rest-=k;micost+=k*cost[i];
            }
        }
        return flow-rest;
    }
    void solve(){
        ll flow=mxflow=micost=0;
        while(spfa())while(flow=dinic(S,INF))mxflow+=flow;
    }
}mf;

有源汇上下界最小费用最大流

struct lrDinic{
    const ll INF=0x3f3f3f3f3f3f3f3f;
    int head[N],ver[M<<1],nxt[M<<1],tot=1,te=0;
    ll edge[M<<1],cost[M<<1],dis[N],mxflow,micost,resflow,rescost;
    ll in[N],out[N];
    void add(int x,int y,ll z,ll w,ll z0=0){
        ver[++tot]=y,edge[tot]=z,cost[tot]=w,nxt[tot]=head[x],head[x]=tot;
        ver[++tot]=x,edge[tot]=z0,cost[tot]=-w,nxt[tot]=head[y],head[y]=tot;
    }
    struct Edge{
        int x,y;
        ll l,r,w;
    }e[M<<1];
    queue<int>q;
    int v[N],now[N],d[N],S,T,rS,rT;
    void clear(){
        memset(head,0,sizeof(head));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        tot=1;te=0;S=T=rS=rT=0;
    }
    bool spfa(){
        memset(dis,0x3f,sizeof(dis));
        memset(v,0,sizeof(v));
        while(q.size())q.pop();
        q.push(S);dis[S]=0;d[S]=v[S]=1;now[S]=head[S];
        while(q.size()){
            int x=q.front();q.pop();
            v[x]=0;
            for(int i=head[x],y;i;i=nxt[i]){
                y=ver[i];
                if(edge[i]&&dis[y]>dis[x]+cost[i]){
                    dis[y]=dis[x]+cost[i];
                    d[y]=d[x]+1;
                    if(!v[y]){
                        q.push(y);
                        v[y]=1;now[y]=head[y];
                    }
                }
            }
        }
        return dis[T]!=INF;
    }
    ll dinic(int x,ll flow){
        if(x==T)return flow;
        ll rest=flow,k;
        for(int i=now[x],y;i&&rest;i=nxt[i]){
            y=ver[i];now[x]=i;
            if(edge[i]&&dis[y]==dis[x]+cost[i]&&d[y]==d[x]+1){
                k=dinic(y,min(edge[i],rest));
                if(!k)d[y]=0;
                edge[i]-=k;edge[i^1]+=k;
                rest-=k;micost+=k*cost[i];
            }
        }
        return flow-rest;
    }
    void solve(){
        ll flow=mxflow=micost=0;
        while(spfa())while(flow=dinic(S,INF))mxflow+=flow;
    }
    bool work(){
        e[++te]={rT,rS,0,INF,0};
        int n=0;
        ll sum=0;resflow=0;rescost=0;
        int bk;
        for(int i=1;i<=te;i++){
            add(e[i].x,e[i].y,e[i].r-e[i].l,e[i].w);
            out[e[i].x]+=e[i].l;
            in[e[i].y]+=e[i].l;
            n=max(n,max(e[i].x,e[i].y));
            rescost+=e[i].l*e[i].w;
        }
        bk=tot;
        S=n+1,T=n+2;
        for(int i=1;i<=n;i++){
            ll c=in[i]-out[i];
            if(c>0)add(S,i,c,0),sum+=c;
            if(c<0)add(i,T,-c,0);
        }
        solve();
        resflow+=edge[bk];
        rescost+=micost;
        if(mxflow!=sum)return 0;
        edge[bk]=edge[bk^1]=0;
        S=rS,T=rT;
        solve();
        resflow+=mxflow;
        rescost+=micost;
        return 1;
    }
}mf;