• 网络流例题学习


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

    首先是模板。

    最大流 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);
        }
    }
  • 相关阅读:
    pyqt5 树节点点击实现多窗口切换
    pyglet self.
    itchat key
    python队列Queue
    Python建立多线程任务并获取每个线程返回值
    利用Python实现多线程聊天功能
    Python3.5+PyQt5多线程+itchat实现微信防撤回桌面版代码
    pyglet player sound
    文件打开的几种访问模式
    pyglet StaticSource
  • 原文地址:https://www.cnblogs.com/zzqsblog/p/5322713.html
Copyright © 2020-2023  润新知