zoukankan      html  css  js  c++  java
  • 【模板】网络流学习笔记

    (还是不熟 好难啊


    HDU1532

    最大流裸题

    Edmonds_Karp算法(bfs)

    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    
    
    int m;
    int g[220][220],pre[220];int bfs(int st,int ed)
    {
        for(int i=1;i<=m;i++)pre[i]=-1;
        int u,w=inf;
        queue<int>que;
        que.push(st);pre[st]=0;
        while(!que.empty())
        {
            u=que.front();que.pop();
            if(u==ed)break;
            for(int i=1;i<=m;i++)
            {
                if(pre[i]==-1&&g[u][i]>0)
                {
                    pre[i]=u;
                    w=min(w,g[u][i]);
                    que.push(i);
                }
            }
        }
        if(pre[ed]==-1)return 0;
        return w;
    }
    
    int E_K(int st,int ed)
    {
        int w,sum=0;
        while(w=bfs(st,ed))
        {
            int u=ed;
            while(u!=st)
            {
                g[pre[u]][u]-=w;
                g[u][pre[u]]+=w;
                u=pre[u];
            }
            sum+=w;
        }
        return sum;
    }
    
    
    int main()
    {
        int n,i,j,k,u,v,w;
        while(~scanf("%d%d",&n,&m))
        {
            memset(g,0,sizeof(g));
            
            for(i=1;i<=n;i++)
            {
                scanf("%d%d%d",&u,&v,&w);
                g[u][v]+=w;
            }
            printf("%d
    ",E_K(1,m));
        }
    }
     
    
    Dinic算法 (是E_K算法的优化 可以快一些 (bfs+dfs))
    
    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    
    
    int m;
    int g[220][220],dep[220];
    
    bool bfs(int st,int ed)
    {
        for(int i=1;i<=m;i++)dep[i]=-1;
        int u;
        queue<int>que;
        que.push(st);dep[st]=0;
        while(!que.empty())
        {
            u=que.front();que.pop();
            for(int i=1;i<=m;i++)
            {
                if(dep[i]==-1&&g[u][i]>0)
                {
                    dep[i]=dep[u]+1;
                    if(i==ed)return 1;
                    que.push(i);
                }
            }
        }
        return dep[ed]!=-1;
    }
    
    int dfs(int st,int ed,int lim)
    {
        if(!lim||st==ed)return lim;
        int w=0,d;
        for(int i=1;i<=m;i++)
        {
            if(dep[i]==dep[st]+1&&g[st][i]>0&&(d=dfs(i,ed,min(g[st][i],lim))))
            {
                g[st][i]-=d;
                g[i][st]+=d;
                w+=d;
                lim-=d;
                if(!lim)break;
            }
        }
        return w;
    }
    
    int Dinic(int st,int ed)
    {
        int sum=0;
        while(bfs(st,ed))sum+=dfs(st,ed,inf);
        return sum;
    }
    
    
    int main()
    {
        int n,i,j,k,u,v,w;
        while(~scanf("%d%d",&n,&m))
        {
            memset(g,0,sizeof(g));
            
            for(i=1;i<=n;i++)
            {
                scanf("%d%d%d",&u,&v,&w);
                g[u][v]+=w;
            }
            printf("%d
    ",Dinic(1,m));
        }
    }
    View Code

    LOJ网络流 24 题」搭配飞行员 (第一题

    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    
    
    int n,m;
    int g[110][110],dep[110];
    
    bool bfs(int st,int ed)
    {
        for(int i=0;i<=n;i++)dep[i]=-1;
        int u;
        queue<int>que;
        que.push(st);dep[st]=0;
        while(!que.empty())
        {
            u=que.front();que.pop();
            for(int i=1;i<=n;i++)
            {
                if(dep[i]==-1&&g[u][i]>0)
                {
                    dep[i]=dep[u]+1;
                    if(i==ed)return 1;
                    que.push(i);
                }
            }
        }
        return dep[ed]!=-1;
    }
    
    int dfs(int st,int ed,int lim)
    {
        if(!lim||st==ed)return lim;
        int w=0,d;
        for(int i=0;i<=n;i++)
        {
            if(dep[i]==dep[st]+1&&g[st][i]>0&&(d=dfs(i,ed,min(g[st][i],lim))))
            {
                g[st][i]-=d;
                g[i][st]+=d;
                w+=d;
                lim-=d;
                if(!lim)break;
            }
        }
        return w;
    }
    
    int Dinic(int st,int ed)
    {
        int sum=0;
        while(bfs(st,ed))sum+=dfs(st,ed,inf);
        return sum;
    }
    
    
    int main()
    {
        int i,j,k,u,v;
        scanf("%d%d",&n,&m);
    //    scanf("%d",&k);
        for(i=1;i<=m;i++)g[0][i]=1;
        for(i=m+1;i<=n;i++)g[i][n+1]=1;
        n++;
    //    while(k--)
        while(~scanf("%d%d",&u,&v))
        {
    //        scanf("%d%d",&u,&v);
            g[u][v]=1;
            
        }
        printf("%d
    ",Dinic(0,n));
    }
    View Code

    洛谷P2756飞行员配对方案问题

    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    
    
    int n,m;
    int g[110][110],dep[110];
    
    bool bfs(int st,int ed)
    {
        for(int i=0;i<=n;i++)dep[i]=-1;
        int u;
        queue<int>que;
        que.push(st);dep[st]=0;
        while(!que.empty())
        {
            u=que.front();que.pop();
            for(int i=1;i<=n;i++)
            {
                if(dep[i]==-1&&g[u][i]>0)
                {
                    dep[i]=dep[u]+1;
                    if(i==ed)return 1;
                    que.push(i);
                }
            }
        }
        return dep[ed]!=-1;
    }
    
    int dfs(int st,int ed,int lim)
    {
        if(!lim||st==ed)return lim;
        int w=0,d;
        for(int i=0;i<=n;i++)
        {
            if(dep[i]==dep[st]+1&&g[st][i]>0&&(d=dfs(i,ed,min(g[st][i],lim))))
            {
                g[st][i]-=d;
                g[i][st]+=d;
                w+=d;
                lim-=d;
                if(!lim)break;
            }
        }
        return w;
    }
    
    int Dinic(int st,int ed)
    {
        int sum=0;
        while(bfs(st,ed))sum+=dfs(st,ed,inf);
        return sum;
    }
    
    
    int main()
    {
        int i,j,k,u,v;
        scanf("%d%d",&m,&n);
        for(i=1;i<=m;i++)g[0][i]=1;
        for(i=m+1;i<=n;i++)g[i][n+1]=1;
        n++;
        scanf("%d%d",&u,&v);
        while(u!=-1&&v!=-1)
        {
            g[u][v]=1;
            scanf("%d%d",&u,&v);
        }
        k=Dinic(0,n);
        if(k==0)puts("No solution!");
        else
        {
            printf("%d
    ",k);
            for(i=1;i<=m;i++)
            {
                for(j=m+1;j<=n;j++)
                if(g[j][i]!=0)printf("%d %d
    ",i,j);
            }
        }
    }
    View Code

    好艰难 我觉得我只会 对着模板抄

    P3381最小费用最大流

    求最大流量下的最小费用

    (为了xxxxxx,尝试用链式前向星来做,还不太习惯)

    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    
    
    struct P{
        int to,flow,dis,next;
    }p[50500<<1];
    int head[50500<<1],pnum;
    
    void add(int from,int to,int flow,int dis)
    {
        p[++pnum].next=head[from];
        p[pnum].to=to;
        p[pnum].flow=flow;
        p[pnum].dis=dis;
        head[from]=pnum;
    }
    
    
    int dis[5050],vis[5050],pre[5050],last[5050],flow[5050];
    
    
    bool spaf_bfs(int s,int t)
    {
        memset(dis,inf,sizeof(dis));
        memset(vis,0,sizeof(vis));
        memset(flow,inf,sizeof(flow));
        queue<int> que;
        que.push(s);dis[s]=0;pre[t]=-1;vis[s]=1;
        while(!que.empty())
        {
            int u=que.front();que.pop();
            vis[u]=0;
            for(int i=head[u];i!=-1;i=p[i].next)
            {
                if(p[i].flow>0&&dis[p[i].to]>dis[u]+p[i].dis)
                {
                    dis[p[i].to]=dis[u]+p[i].dis;
                    pre[p[i].to]=u;
                    last[p[i].to]=i;
                    flow[p[i].to]=min(flow[u],p[i].flow);
                    if(!vis[p[i].to])
                    {
                        vis[p[i].to]=1;
                        que.push(p[i].to);
                    }
                }
            }
        }
        return pre[t]!=-1;
    }
    
    void solve(int s,int t,int &w,int &c)
    {
        w=0;c=0;
        while(spaf_bfs(s,t))
        {
            int u=t;
            w+=flow[t];
            c+=flow[t]*dis[t];
            while(u!=s)
            {
                p[last[u]].flow-=flow[t];
                p[last[u]^1].flow+=flow[t];
                u=pre[u];
            }
        }
    }
    
    
    
    int main()
    {
        memset(head,-1,sizeof(head));pnum=-1;
        int n,m,s,t,i,u,v,w,f;
        scanf("%d%d%d%d",&n,&m,&s,&t);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d%d",&u,&v,&w,&f);
            add(u,v,w,f);
            add(v,u,0,-f);
        }
        solve(s,t,u,v);
        printf("%d %d
    ",u,v);
    }
    View Code

    Gasoline

    最大流+二分

    借着别人的博客的二分 总算补完了这一题。

    二分求最小/最大值技巧还不太熟。一直没能想到。

    (用E_K算法会超时,用Dinic不会)

    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    
    struct P{
        int next,to,flow;
    }p[22200<<1];
    int head[22200<<1],pnum;
    struct PP{
        int u,v,t;
        PP(){}
        PP(int uu,int vv,int tt){u=uu;v=vv;t=tt;}
    }pp[20200];
    
    
    void add(int from,int to,int flow)
    {
        p[++pnum].next=head[from];
        p[pnum].to=to;
        p[pnum].flow=flow;
        head[from]=pnum;
    }
    
    int x,y,c,n,allsum,a[2020],b[2020];
    
    int pre[2020],dep[2020];
    bool vis[2020];
    
    
    bool bfs(int st,int ed)
    {
        memset(dep,-1,sizeof(dep));
        int u;
        queue<int>que;
        que.push(st);dep[st]=0;
        while(!que.empty())
        {
            u=que.front();que.pop();
            for(int i=head[u];i!=-1;i=p[i].next)
            {
                if(dep[p[i].to]==-1&&p[i].flow)
                {
                    dep[p[i].to]=dep[u]+1;
                    if(p[i].to==ed)return 1;
                    que.push(p[i].to);
                }
            }
        }
        return dep[ed]!=-1;
    }
    
    int dfs(int st,int ed,int lim)
    {
        if(!lim||st==ed)return lim;
        int w=0,d;
        for(int i=head[st];i!=-1;i=p[i].next)
        {
            if(dep[p[i].to]==dep[st]+1&&(d=dfs(p[i].to,ed,min(p[i].flow,lim))))
            {
                p[i].flow-=d;
                p[i^1].flow+=d;
                w+=d;
                lim-=d;
                if(!lim)break;
            }
        }
        return w;
    }
    int Dinic(int st,int ed)
    {
        int sum=0;
        while(bfs(st,ed))sum+=dfs(st,ed,inf);
        return sum;
    }
    /*
    int bfs(int st,int ed)
    {
        memset(vis,0,sizeof(vis));
        int u,w=inf;
        queue<int>que;
        que.push(st);pre[st]=pre[ed]=-1;vis[st]=1;
        while(!que.empty())
        {
            u=que.front();que.pop();
            if(u==ed)break;
            for(int i=head[u];i!=-1;i=p[i].next)
            {
                if(vis[p[i].to]==0&&p[i].flow>0)
                {
                    vis[p[i].to]=1;
                    pre[p[i].to]=i;
                    w=min(w,p[i].flow);
                    que.push(p[i].to);
                }
            }
        }
        if(pre[ed]==-1)return 0;
        return w;
    }
    
    int E_K(int st,int ed)
    {
        int w,sum=0;
        while(w=bfs(st,ed))
        {
            for(int i=pre[ed];i!=-1;i=pre[p[i^1].to])
            {
                p[i].flow-=w;
                p[i^1].flow+=w;
            }
            sum+=w;
        }
        return sum;
    }*/
    
    bool check(int mid)
    {
        int i;
        memset(head,-1,sizeof(head));pnum=-1;
        for(i=1;i<=y;i++)
        {
            add(0,i,a[i]);
            add(i,0,0);
        }
        for(i=1;i<=x;i++)
        {
            add(y+i,n,b[i]);
            add(n,y+i,0);
        }
        for(i=1;i<=c;i++)
        {
            if(pp[i].t<=mid)
            {
                add(pp[i].u,pp[i].v+y,inf);
                add(pp[i].v+y,pp[i].u,0);
            }
        }
        int maxflow=Dinic(0,n);
        if(maxflow==allsum)return 1;
        return 0;
    }
    
    int main()
    {
        allsum=0;
        int i,j,k,w;
        int u,v,t,l,r=0,mid,ans;
        scanf("%d%d%d",&x,&y,&c);
        n=x+y+1;
        for(i=1;i<=x;i++)
        {
            scanf("%d",&b[i]);
            allsum+=b[i];
        }
        for(i=1;i<=y;i++)scanf("%d",&a[i]);
        for(i=1;i<=c;i++)
        {
            scanf("%d%d%d",&v,&u,&t);
            pp[i]=PP(u,v,t);
            r=max(r,t);
        }
        l=0;ans=-1;r++; 
        while(l<r)
        {
            mid=(l+r)>>1;
            if(check(mid))
            {
                ans=mid;
                r=mid;
            }
            else l=mid+1;
        }
        printf("%d
    ",ans);
    }
    View Code

    LOJ 「网络流 24 题」太空飞行计划 (第二题

    1.初学网络流,从这道题的洛谷题解知道了一件事:

      Dinic最后一次bfs的dep(深度)数组标记了与源点连通的点(即,未被初始化标记的点 就是 与最终确定与源点连通的点),有利于最后方案的输出。

      下一题告诉我这是假的QAQ。。所以通用方法是什么/(ㄒoㄒ)/~~

    2.据说 这道题是最小割的题。我用最大流做的,不懂为什么是最小割?

       

          因为:最小割==最大流

      有趣的是:一直想不到,正确建图后,总的利润-最大流的花费 会等于 最大盈利。但是按这道题的正确建图方法去思考,正好是这样!

    3.这道题,据说:

      这道题数据是在windows生成的,输入数据中所有的换行都是' '而不是' '
      读入某实验需要用到的仪器编号的时候,可以这么读入

    char tools[10000];
    memset(tools,0,sizeof tools);
    cin.getline(tools,10000);
    int ulen=0,tool;
    while (sscanf(tools+ulen,"%d",&tool)==1)//之前已经用scanf读完了赞助商同意支付该实验的费用
    {//tool是该实验所需仪器的其中一个      
        //这一行,你可以将读进来的编号进行储存、处理,如连边。
        if (tool==0) 
            ulen++;
        else {
            while (tool) {
                tool/=10;
                ulen++;
            }
        }
        ulen++;
    }

    代码:

    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const int maxn=3e3+50;
    
    
    struct P{
        int to,flow,next;
    }p[maxn];
    int head[maxn],pnum;
    
    void add(int from,int to,int flow)
    {
        p[++pnum].next=head[from];
        p[pnum].to=to;
        p[pnum].flow=flow;
        head[from]=pnum;
    }
    
    
    int dis[maxn],vis[maxn],dep[maxn],flow[maxn];
    
    
    bool bfs(int st,int ed)
    {
        memset(dep,-1,sizeof(dep));
        int u;
        queue<int>que;
        que.push(st);dep[st]=0;
        while(!que.empty())
        {
            u=que.front();que.pop();
            for(int i=head[u];i!=-1;i=p[i].next)
            {
                if(dep[p[i].to]==-1&&p[i].flow)
                {
                    dep[p[i].to]=dep[u]+1;
                    if(p[i].to==ed)return 1;
                    que.push(p[i].to);
                }
            }
        }
        return dep[ed]!=-1;
    }
    int dfs(int st,int ed,int lim)
    {
        if(!lim||st==ed)return lim;
        int w=0,d;
        for(int i=head[st];i!=-1;i=p[i].next)
        {
            if(dep[p[i].to]==dep[st]+1&&p[i].flow&&(d=dfs(p[i].to,ed,min(p[i].flow,lim))))
            {
                p[i].flow-=d;
                p[i^1].flow+=d;
                w+=d;
                lim-=d;
                if(!lim)break;
            }
        }
        return w;
    }
    int Dinic(int st,int ed)
    {
        int sum=0;
        while(bfs(st,ed))sum+=dfs(st,ed,inf);
        return sum;
    }
    
    //这道题数据是在windows生成的
    //输入数据中所有的换行都是'
    '而不是'
    '
    
    int main()
    {
        memset(head,-1,sizeof(head));pnum=-1;
        int m,n,i,j,k,w,ed,sum=0,ans;
        scanf("%d%d",&m,&n);
        ed=m+n+1;
        char tools[10000];//
        
        for(i=1;i<=m;i++)
        {
            scanf("%d",&w);
            sum+=w;
            add(0,i,w);
            add(i,0,0);
            memset(tools,0,sizeof tools);
            cin.getline(tools,10000);
            int ulen=0,tool;
            while (sscanf(tools+ulen,"%d",&tool)==1)//之前已经用scanf读完了赞助商同意支付该实验的费用
            {//tool是该实验所需仪器的其中一个      
                add(i,m+tool,inf);
                add(m+tool,i,0);//这一行,你可以将读进来的编号进行储存、处理,如连边。
                if (tool==0) 
                    ulen++;
                else {
                    while (tool) {
                        tool/=10;
                        ulen++;
                    }
                }
                ulen++;
            }
        }
        for(i=1;i<=n;i++)
        {
            scanf("%d",&w);
            add(m+i,ed,w);
            add(ed,m+i,0);
        }
        ans=sum-Dinic(0,ed);
        for(i=1,k=0;i<=m;i++)
        {
            if(dep[i]!=-1)
            {
                if(k)putchar(32);
                k=1;
                printf("%d",i);
            }
        }
        putchar(10);
        for(i=m+1,k=0;i<ed;i++)
        {
            if(dep[i]!=-1)
            {
                if(k)putchar(32);
                k=1;
                printf("%d",i-m);
            }
        }
        putchar(10);
        printf("%d
    ",ans);
    }
    View Code

    洛谷P2764 最小路径覆盖问题 

    6002「网络流 24 题」最小路径覆盖

    路径输出是一个问题啊。本来以为用if(dep[i]!=-1)来找就行了,结果发现是假的

    这道题由于流量只是1,所以就用if(p[i].w==0&&i&1==0)来找,但是如果流量等于2,3,4....n呢?QAQ

    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const int maxn=6e3+5;
    
    struct P{
        int to,w,next;
    }p[maxn<<2];
    int head[355],cnt;
    
    void add(int u,int v,int w)
    {
        p[cnt].to=v;
        p[cnt].w=w;
        p[cnt].next=head[u];
        head[u]=cnt++;
    }
    
    int n;
    
    int dep[355];
    
    bool bfs(int st,int ed)
    {
        memset(dep,-1,sizeof(dep));
        int u;
        queue<int>que;
        que.push(st);dep[st]=0;
        while(!que.empty())
        {
            u=que.front();que.pop();
            for(int i=head[u];i!=-1;i=p[i].next)
            {
                if(dep[p[i].to]==-1&&p[i].w)
                {
                    dep[p[i].to]=dep[u]+1;
                    if(p[i].to==ed)return 1;
                    que.push(p[i].to);
                }
            }
        }
        return dep[ed]!=-1;
    }
    
    int dfs(int st,int ed,int lim)
    {
        if(!lim||st==ed)return lim;
        int w=0,d;
        for(int i=head[st];i!=-1;i=p[i].next)
        {
            if(dep[p[i].to]==dep[st]+1&&p[i].w&&(d=dfs(p[i].to,ed,min(p[i].w,lim))))
            {
                p[i].w-=d;
                p[i^1].w+=d;
                w+=d;
                lim-=d;
                if(!lim)break;
            }    
        }
        return w;
    }
    
    int Dinic(int st,int ed)
    {
        int sum=0;
        while(bfs(st,ed))sum+=dfs(st,ed,inf);
        return sum;
    }
    
    
    int son[335];
    bool isson[335];
    void getline()
    {
        int u,v,f;
        for(u=1;u<=n;u++)
        {
            f=u;
            for(int i=head[u];i!=-1;i=p[i].next)
            {
                if(p[i].w||i&1)continue;
                v=p[i].to;
                if(v>n)v-=n;
                son[f]=v;f=v;
                isson[v]=1;
                p[i].w=-1;
            }
        }
    }
    
    int main()
    {
        memset(head,-1,sizeof(head));
        
        int m,i,u,v,ed,res;
        scanf("%d%d",&n,&m);ed=n*2+1;
        for(i=1;i<=n;i++)
        {
            add(0,i,1);add(i,0,0);
            add(i+n,ed,1);add(ed,i+n,0);
        }
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            add(u,n+v,1);add(n+v,u,0);
        }
        
        res=n-Dinic(0,ed);
        
        
        getline();
        for(i=1;i<=n;i++)
        {
            if(isson[i])continue;
            u=i;
            printf("%d ",u);
            while(son[u])
            {
                u=son[u];
                printf("%d ",u);
            }
            printf("
    ");
        }
        printf("%d
    ",res);
        
    }
    View Code

    然后

    6003「网络流 24 题」魔术球

    这个可以化为最小路径覆盖问题。用上面的代码输出路径。

    (要不是放在网络流里,这怎么可能想到嘛)

    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const int maxn=7e4+5;
    
    struct P{
        int to,w,next;
    }p[maxn<<2];
    int head[maxn],cnt;
    
    void add(int u,int v,int w)
    {
        p[cnt].to=v;
        p[cnt].w=w;
        p[cnt].next=head[u];
        head[u]=cnt++;
    }
    
    int n;
    
    int dep[maxn];
    
    bool bfs(int st,int ed)
    {
        memset(dep,-1,sizeof(dep));
        int u;
        queue<int>que;
        que.push(st);dep[st]=0;
        while(!que.empty())
        {
            u=que.front();que.pop();
            for(int i=head[u];i!=-1;i=p[i].next)
            {
                if(dep[p[i].to]==-1&&p[i].w)
                {
                    dep[p[i].to]=dep[u]+1;
                    if(p[i].to==ed)return 1;
                    que.push(p[i].to);
                }
            }
        }
        return dep[ed]!=-1;
    }
    
    int dfs(int st,int ed,int lim)
    {
        if(!lim||st==ed)return lim;
        int w=0,d;
        for(int i=head[st];i!=-1;i=p[i].next)
        {
            if(dep[p[i].to]==dep[st]+1&&p[i].w&&(d=dfs(p[i].to,ed,min(p[i].w,lim))))
            {
                p[i].w-=d;
                p[i^1].w+=d;
                w+=d;
                lim-=d;
                if(!lim)break;
            }    
        }
        return w;
    }
    
    int Dinic(int st,int ed)
    {
        int sum=0;
        while(bfs(st,ed))sum+=dfs(st,ed,inf);
        return sum;
    }
    
    
    int son[maxn];
    bool isson[maxn];
    void getline()
    {
        int u,v,f;
        for(u=1;u<=n;u++)
        {
            f=u;
            for(int i=head[u];i!=-1;i=p[i].next)
            {
                if(p[i].w||i&1)continue;
                v=p[i].to;
                if(v>n)v-=n;
                son[f]=v;f=v;
                isson[v]=1;
                p[i].w=-1;
            }
        }
    }
    
    void addedge(int k)
    {
        for(int i=1;i<=k;i++)
        {
            int up=i*i;
            for(int j=1;j<<1<=up;j++)
            {
                if(up-j>n)continue;
                if(j<<1==up)break;
                add(j,up-j+n,1);
                add(up-j+n,j,0);
            }
        }
    }
    
    int main()
    {
        memset(head,-1,sizeof(head));
        int i,k,u,v,ed,res;
        scanf("%d",&k);
        n=(k+1)*(k+1)/2-1;
        ed=n*2+1;
        for(i=1;i<=n;i++)
        {
            add(0,i,1);add(i,0,0);
            add(i+n,ed,1);add(ed,i+n,0);
        }
        addedge(k);
        
        Dinic(0,ed);
        
        printf("%d
    ",n);
        getline();
        for(i=1;i<=n;i++)
        {
            if(isson[i])continue;
            u=i;
            printf("%d",u);
            while(son[u])
            {
                u=son[u];
                printf(" %d",u);
            }
            printf("
    ");
        }
    }
    View Code

     6004 「网络流 24 题」圆桌聚餐

    满流的路径输出是那个流最后为零,那么它就与源点连通。

    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const int maxn=5e4+5;
    
    struct P{
        int to,w,next;
    }p[maxn<<2];
    int head[maxn],cnt;
    
    void add(int u,int v,int w)
    {
        p[cnt].to=v;
        p[cnt].w=w;
        p[cnt].next=head[u];
        head[u]=cnt++;
    }
    
    int n;
    
    int dep[455];
    
    bool bfs(int st,int ed)
    {
        memset(dep,-1,sizeof(dep));
        int u;
        queue<int>que;
        que.push(st);dep[st]=0;
        while(!que.empty())
        {
            u=que.front();que.pop();
            for(int i=head[u];i!=-1;i=p[i].next)
            {
                if(dep[p[i].to]==-1&&p[i].w)
                {
                    dep[p[i].to]=dep[u]+1;
                    if(p[i].to==ed)return 1;
                    que.push(p[i].to);
                }
            }
        }
        return dep[ed]!=-1;
    }
    
    int dfs(int st,int ed,int lim)
    {
        if(!lim||st==ed)return lim;
        int w=0,d;
        for(int i=head[st];i!=-1;i=p[i].next)
        {
            if(dep[p[i].to]==dep[st]+1&&p[i].w&&(d=dfs(p[i].to,ed,min(p[i].w,lim))))
            {
                p[i].w-=d;
                p[i^1].w+=d;
                w+=d;
                lim-=d;
                if(!lim)break;
            }    
        }
        return w;
    }
    
    int Dinic(int st,int ed)
    {
        int sum=0;
        while(bfs(st,ed))sum+=dfs(st,ed,inf);
        return sum;
    }
    
    
    vector<int>allfa[455];
    void getline(int a)
    {
        int u,v;
        for(u=a;u<=n;u++)
        {
            for(int i=head[u];i!=-1;i=p[i].next)
            {
                v=p[i].to;
                if(p[i].w!=0||i&1)continue;
                allfa[v].push_back(u);
            }
        }
    }
    
    int main()
    {
        memset(head,-1,sizeof(head));
        int i,j,u,v,w,ed,res,sum=0;
        scanf("%d%d",&u,&v);
        n=u+v;
        ed=n+1;
        for(i=1;i<=u;i++)
        {
            scanf("%d",&w);
            sum+=w;
            add(i,ed,w);add(ed,i,0);
        }
        for(i=1;i<=v;i++)
        {
            scanf("%d",&w);
            add(0,u+i,w);add(u+i,0,0);
            for(j=1;j<=u;j++)
            {
                add(u+i,j,1);
                add(j,u+i,0);
            }
        }
        
        res=Dinic(0,ed);
        if(res!=sum)
        {
            printf("0
    ");return 0;
        }
        printf("1
    ");
        getline(u+1);
        for(i=1;i<=u;i++)
        {
            for(j=0;j<allfa[i].size();j++)printf("%d ",allfa[i][j]-u);
            putchar(10);
        }
    }
    View Code

     6005 「网络流 24 题」最长递增子序列

    一件事:网络流可以在计算出当前最大流后,放松流(边)的限制再累加求扩充流量后的最大流。不影响正确性。

    这道题依旧是割裂点。

    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const int maxn=1e6+50;
    
    struct P{
        int to,w,next;
    }p[maxn];
    int head[1050],cnt,ed,a[1050],dp[1050];
    
    void addline(int u,int v,int w)
    {
        p[cnt].w=w;
        p[cnt].to=v;
        p[cnt].next=head[u];
        head[u]=cnt++;
    }
    void add(int u,int v,int w)
    {
        addline(u,v,w);
        addline(v,u,0);
    }
    
    
    int dep[1050];
    bool bfs(int st,int ed)
    {
        memset(dep,-1,sizeof(dep));
        int u;
        queue<int>que;
        que.push(st);dep[st]=0;
        while(!que.empty())
        {
            u=que.front();que.pop();
            for(int i=head[u];i!=-1;i=p[i].next)
            {
                if(dep[p[i].to]==-1&&p[i].w)
                {
                    dep[p[i].to]=dep[u]+1;
                    if(p[i].to==ed)return 1;
                    que.push(p[i].to);
                }
            }
        }
        return dep[ed]!=-1;
    }
    
    int dfs(int st,int ed,int lim)
    {
        if(!lim||st==ed)return lim;
        int w=0,d;
        for(int i=head[st];i!=-1;i=p[i].next)
        {
            if(dep[p[i].to]==dep[st]+1&&p[i].w&&(d=dfs(p[i].to,ed,min(p[i].w,lim))))
            {
                p[i].w-=d;
                p[i^1].w+=d;
                w+=d;
                lim-=d;
                if(!lim)break;
            }
        }
        return w;
    }
    int sum=0;
    int Dinic(int st,int ed)
    {
        while(bfs(st,ed))sum+=dfs(st,ed,inf);
        return sum;
    }
    
    int main()
    {
        memset(head,-1,sizeof(head));
        int n,i,j,k,u,len=1;
        scanf("%d",&n);ed=2*n+1;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);dp[i]=1;add(i,i+n,1);
        }
        for(i=n-1;i>=1;i--)// dec
        {
            for(j=n;j>=i+1;j--)
            {
                if(a[i]>a[j])continue;
                dp[i]=max(dp[i],dp[j]+1);
                len=max(len,dp[i]);
            }
            for(j=n;j>=i+1;j--)
            {
                if(dp[i]==dp[j]+1&&a[i]<=a[j])add(n+i,j,1);
            }
        }
        printf("%d
    ",len);
    //    for(i=1;i<=n;i++)printf("#%d# ",dp[i]);
        for(i=1;i<=n;i++)
        {
            if(dp[i]==len)add(0,i,1);
            if(dp[i]==1)add(n+i,ed,1);
        }
        printf("%d
    ",Dinic(0,ed));
        if(n==1)
        {
            printf("1
    ");
            return 0;
        }
        if(dp[1]==len)add(0,1,inf),add(1,n+1,inf);
        if(dp[n]==1)add(n,n*2,inf),add(n*2,ed,inf);
        printf("%d
    ",Dinic(0,ed));
        
    }
    View Code

    6007 「网络流 24 题」方格取数

    再说一次,一件事:最小割=最大流。

    即使是放在网络流,即使告诉我是最小割,我也想不到该怎么做。

    暴风哭泣。┭┮﹏┭┮

    推荐洛谷题解,看一遍豁然开朗一遍,下一次又重新看一遍,豁然开朗一遍。(┬_┬)

    题解说,二分图,然后源点连奇点,汇点连偶点,流量为点权,中间的点,互斥的点用inf流连接。题中同奇偶性必不互斥。

    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const int maxn=1e4+50;
    
    struct P{
        int to,w,next;
    }p[maxn<<3];
    int head[maxn],cnt;
    
    void addline(int u,int v,int w)
    {
        p[cnt].w=w;
        p[cnt].to=v;
        p[cnt].next=head[u];
        head[u]=cnt++;
    }
    void add(int u,int v,int w)
    {
        addline(u,v,w);
        addline(v,u,0);
    }
    
    int dep[maxn];
    
    
    bool bfs(int st,int ed)
    {
        memset(dep,-1,sizeof(dep));
        int u;
        queue<int>que;
        que.push(st);dep[st]=0;
        while(!que.empty())
        {
            u=que.front();que.pop();
            for(int i=head[u];i!=-1;i=p[i].next)
            {
                if(dep[p[i].to]==-1&&p[i].w)
                {
                    dep[p[i].to]=dep[u]+1;
                    if(p[i].to==ed)return 1;
                    que.push(p[i].to);
                }
            }
        }
        return dep[ed]!=-1;
    }
    int dfs(int st,int ed,int lim)
    {
        if(!lim||st==ed)return lim;
        int w=0,d;
        for(int i=head[st];i!=-1;i=p[i].next)
        {
            if(dep[p[i].to]==dep[st]+1&&p[i].w&&(d=dfs(p[i].to,ed,min(p[i].w,lim))))
            {
                p[i].w-=d;
                p[i^1].w+=d;
                w+=d;
                lim-=d;
                if(!lim)break;
            }
        }
        return w;
    }
    int Dinic(int st,int ed)
    {
        int sum=0;
        while(bfs(st,ed))sum+=dfs(st,ed,inf);
        return sum;
    }
    
    int main()
    {
        memset(head,-1,sizeof(head));
        int n,m,st,ed,a,u,sum=0;
        scanf("%d%d",&n,&m);
        st=0;ed=n*m+1;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&a);
                sum+=a;
                u=(i-1)*m+j;
                if((i+j)%2)
                {
                    add(st,u,a);
                    if(j>1)add(u,u-1,inf);
                    if(i>1)add(u,u-m,inf);
                    if(j<m)add(u,u+1,inf);
                    if(i<n)add(u,u+m,inf);
                }
                else add(u,ed,a);
            }
        }
        printf("%d
    ",sum-Dinic(st,ed));
    }
    View Code

  • 相关阅读:
    LeetCode:Plus One
    LeetCode:Text Justification
    LeetCode:Sqrt(x)
    LeetCode:Climbing Stairs(编程之美2.9-斐波那契数列)
    LeetCode:Simplify Path
    LeetCode:Edit Distance
    LeetCode:Set Matrix Zeroes
    LeetCode:Search in Rotated Sorted Array I II
    LeetCode:Search a 2D Matrix
    LeetCode:Sort Colors
  • 原文地址:https://www.cnblogs.com/kkkek/p/11568623.html
Copyright © 2011-2022 走看看