网络流例题学习

之前似乎网络流的建图题做得比较少啊…现在来做一点。

首先是模板。

最大流 poj1273 Drainage Ditches

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <limits>
#include <set>
#include <map>
using namespace std;
#define SZ 233333
int n,M=1;
typedef long long ll;
int fst[SZ],nxt[SZ],vb[SZ]; ll cap[SZ];
void ad_dl(int a,int b,ll c)
{
    ++M; nxt[M]=fst[a]; fst[a]=M; vb[M]=b; cap[M]=c;
}
void addl(int a,int b,ll c)
{
    ad_dl(a,b,c); ad_dl(b,a,0);
}
int S,T,q[SZ],d[SZ];
bool bfs()
{
    memset(d,-1,sizeof(d));
    d[S]=0; q[1]=S; int h=1,t=2;
    while(h!=t)
    {
        int cur=q[h++];
        for(int e=fst[cur];e;e=nxt[e])
        {
            int b=vb[e];
            if(d[b]==-1&&cap[e]);else continue;
            d[b]=d[cur]+1; q[t++]=b;
        }
    }
    return d[T]!=-1;
}
ll dfs(int x,ll f)
{
    if(f<=0) return 0;
    if(x==T) return f;
    ll ca=0;
    for(int e=fst[x];e;e=nxt[e])
    {
        int b=vb[e];
        if(d[b]!=d[x]+1) continue;
        ll w=dfs(b,min(cap[e],f-ca));
        cap[e]-=w; cap[e^1]+=w; ca+=w;
        if(ca==f) break;
    }
    if(!ca) d[x]=-1;
    return ca;
}
#define inf 100000000000000000LL
ll dinic()
{
    ll ans=0;
    while(bfs()) ans+=dfs(S,inf);
    return ans;
}
int main()
{
    int m;
    while(scanf("%d%d",&m,&n)!=EOF)
    {
        memset(fst,0,sizeof(fst)); M=1;
        for(int i=1;i<=m;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            addl(a,b,c);
        }
        S=1; T=n;
        printf("%d
",dinic());
    }
}

最小费用最大流 poj2135 Farm Tour

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <limits>
#include <set>
#include <map>
using namespace std;
#define SZ 233333
typedef long long ll;
int M=1,S,T,fst[SZ],nxt[SZ],va[SZ],vb[SZ];
ll cap[SZ],cost[SZ];
void ad_dl(int a,int b,ll ca,ll co)
{
    ++M; nxt[M]=fst[a]; fst[a]=M; va[M]=a; vb[M]=b; cap[M]=ca; cost[M]=co;
}
void addl(int a,int b,ll ca,ll co) {ad_dl(a,b,ca,co); ad_dl(b,a,0,-co);}
ll dis[SZ]; int n,q[SZ],fe[SZ];
bool inq[SZ];
bool spfa()
{
    ll inf=2000000000000000LL;
    for(int i=1;i<=n;i++) dis[i]=inf;
    inq[S]=1; q[1]=S; dis[S]=0; int h=1,t=2;
    while(h!=t)
    {
        int cur=q[h++]; h&=131071;
        for(int e=fst[cur];e;e=nxt[e])
        {
            if(!cap[e]||dis[vb[e]]<=dis[cur]+cost[e]) continue;
            int b=vb[e]; ll co=cost[e]; //!!!
            dis[b]=dis[cur]+co; fe[b]=e;
            if(!inq[b]) {inq[b]=1; q[t++]=b; t&=131071;}
        }
        inq[cur]=0;
    }
    return dis[T]!=inf;
}
ll mcf()
{
    ll ans=0;
    while(spfa())
    {
        ll cur=2000000000000000LL;
        for(int i=fe[T];i;i=fe[va[i]]) cur=min(cur,cap[i]);
        for(int i=fe[T];i;i=fe[va[i]])
        {
            ans+=cur*cost[i];
            cap[i]-=cur; cap[i^1]+=cur;
        }
    }
    return ans;
}
int main()
{
    int m; scanf("%d%d",&n,&m); n+=2;
    S=1; T=n;
    addl(1,2,2,0); addl(T-1,T,2,0);
    while(m--)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        addl(a+1,b+1,1,c);
        addl(b+1,a+1,1,c);
    }
    printf("%d
",(int)mcf());
}

无源汇上下界最大流 zoj2314 Reactor Cooling

加超级源汇点,对于一条容量在[a,b]之间的边,把容量改为[0,b-a],然后为了容量守恒,考察过每一个点的入a-出a,设它为du,如果du>0,超级源往这个点连一条容量为du的边,如果du<0,这个点往超级汇连一条容量为-du的边。最后如果所有附加边都满流(也就是最大流等于所有du>0的之和)就有可行解。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <limits>
#include <set>
#include <map>
using namespace std;
#define SZ 233333
int n,M=1;
typedef long long ll;
int fst[SZ],nxt[SZ],vb[SZ],du[SZ],id[SZ],ans[SZ],cap[SZ];
void ad_dl(int a,int b,int c,int i)
{
    ++M; nxt[M]=fst[a]; fst[a]=M; vb[M]=b; cap[M]=c; id[M]=i;
}
void addl(int a,int b,int c,int i)
{
    ad_dl(a,b,c,i); ad_dl(b,a,0,0);
}
int S,T,q[SZ],d[SZ];
bool bfs()
{
    memset(d,-1,sizeof(d));
    d[S]=0; q[1]=S; int h=1,t=2;
    while(h!=t)
    {
        int cur=q[h++];
        for(int e=fst[cur];e;e=nxt[e])
        {
            int b=vb[e];
            if(d[b]==-1&&cap[e]);else continue;
            d[b]=d[cur]+1; q[t++]=b;
        }
    }
    return d[T]!=-1;
}
int dfs(int x,int f)
{
    if(f<=0) return 0;
    if(x==T) return f;
    int ca=0;
    for(int e=fst[x];e;e=nxt[e])
    {
        int b=vb[e];
        if(d[b]!=d[x]+1) continue;
        int w=dfs(b,min(cap[e],f-ca));
        cap[e]-=w; cap[e^1]+=w; ca+=w;
        if(ca==f) break;
    }
    if(!ca) d[x]=-1;
    return ca;
}
#define inf 100000000000000000LL
int dinic()
{
    int ans=0;
    while(bfs()) ans+=dfs(S,inf);
    return ans;
}
int main()
{
    int m,T_T; scanf("%d",&T_T);
    while(T_T--)
    {
        scanf("%d%d",&n,&m);
        memset(fst,0,sizeof(fst));
        memset(du,0,sizeof(du));
        M=1; n+=2;
        for(int i=1;i<=m;i++)
        {
            int a,b,c,d;
            scanf("%d%d%d%d",&a,&b,&c,&d);
            addl(a+1,b+1,d-c,i); ans[i]=c;
            du[a+1]-=c; du[b+1]+=c;
        }
        int exp=0;
        for(int i=2;i<n;i++)
        {
            if(du[i]>0) addl(1,i,du[i],0), exp+=du[i];
            else if(du[i]<0) addl(i,n,-du[i],0);
        }
        S=1; T=n; int dd=dinic();
        if(exp!=dd) {printf("NO

"); continue;}
        printf("YES
");
        for(int i=2;i<=M;i++) ans[id[i]]+=cap[i^1];
        for(int i=1;i<=m;i++) printf("%d
",ans[i]);
        putchar(10);
    }
}

有源汇上下界最大流 zoj3229 Shoot the Bullet

先判断是否存在可行流:我们从汇点到源点加一条没下界,上界无穷大的边,然后按上面无源汇的做法来做,这样就可以判出可行流。当有可行流时,按原来的源点和汇点再跑一次最大流即可。

写起来十分excited

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <limits>
#include <set>
#include <map>
using namespace std;
#define SZ 233333
int n,M=1;
typedef long long ll;
int fst[SZ],nxt[SZ],vb[SZ],du[SZ],ans[SZ],cap[SZ];
void ad_dl(int a,int b,int c)
{
    ++M; nxt[M]=fst[a]; fst[a]=M; vb[M]=b; cap[M]=c;
}
void addl(int a,int b,int c)
{
    ad_dl(a,b,c); ad_dl(b,a,0);
}
int S,T,q[SZ],d[SZ];
bool bfs()
{
    memset(d,-1,sizeof(d));
    d[S]=0; q[1]=S; int h=1,t=2;
    while(h!=t)
    {
        int cur=q[h++];
        for(int e=fst[cur];e;e=nxt[e])
        {
            int b=vb[e];
            if(d[b]==-1&&cap[e]);else continue;
            d[b]=d[cur]+1; q[t++]=b;
        }
    }
    return d[T]!=-1;
}
int dfs(int x,int f)
{
    if(f<=0) return 0;
    if(x==T) return f;
    int ca=0;
    for(int e=fst[x];e;e=nxt[e])
    {
        int b=vb[e];
        if(d[b]!=d[x]+1) continue;
        int w=dfs(b,min(cap[e],f-ca));
        cap[e]-=w; cap[e^1]+=w; ca+=w;
        if(ca==f) break;
    }
    if(!ca) d[x]=-1;
    return ca;
}
#define inf 1000000000
int dinic()
{
    int ans=0;
    while(bfs()) ans+=dfs(S,inf);
    return ans;
}
int mr[666][233],ii[666][233],cs[233];
void Addl(int a,int b,int l,int r)
{
    addl(a,b,r-l); du[a]-=l; du[b]+=l;
}
int main()
{
    int m,nn;
    while(scanf("%d%d",&nn,&m)!=-1)
    {
        memset(fst,0,sizeof(fst));
        memset(du,0,sizeof(du));
        M=1; n=nn+m+2;
        int rs=n-1,rt=n;
        for(int i=1;i<=m;i++)
        {
            int g;
            scanf("%d",&g);
            Addl(i+nn,rt,g,1000000000);
        }
        for(int i=1;i<=nn;i++)
        {
            int d;
            scanf("%d%d",cs+i,&d);
            Addl(rs,i,0,d);
            for(int j=1;j<=cs[i];j++)
            {
                int t,l,r;
                scanf("%d%d%d",&t,&l,&r);
                Addl(i,t+nn+1,l,r);
                mr[i][j]=M; ii[i][j]=l;
            }
        }
        Addl(rt,rs,0,1000000000);
        n+=2; S=n-1; T=n;
        int exp=0;
        for(int i=1;i<S;i++)
        {
            if(du[i]>0) addl(S,i,du[i]), exp+=du[i];
            else if(du[i]<0) addl(i,T,-du[i]);
        }
        int dd=dinic();
        if(exp!=dd) {printf("-1

"); continue;}
        S=rs; T=rt; dd=dinic();
        printf("%d
",dd);
        for(int i=1;i<=nn;i++)
        {
            for(int j=1;j<=cs[i];j++) printf("%d
",cap[mr[i][j]]+ii[i][j]);
        }
        putchar(10);
    }
}
原文地址:https://www.cnblogs.com/zzqsblog/p/5322713.html