zoukankan      html  css  js  c++  java
  • 最大流练习题

    一,无源网络流的建模

    https://www.luogu.org/problemnew/show/P1231 

    题意,给你n1本书,n2本练习册,n3本答案,给你这些书和答案对应关系,问你最多能组成多少本书册。

    由于需要书,练习册,答案三件套才能组成完整书册,将书复制成两份,一份与练习册建立边,一份与答案建立边,

    建立源点和汇点,跑一边最大流就能解决

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=100000;
    const int INF=0x3fffffff;
    struct Dinic
    {
        struct Edge
        {
            int from,to,cap,flow;
        };
        int n,m,s,t;
        vector<Edge>edges;
        vector<int>G[maxn];
        bool vis[maxn];
        int d[maxn];
        int cur[maxn];
    
        void AddEdge(int from,int to,int cap)
        {
            edges.push_back((Edge)
            {
                from,to,cap,0
            });
            edges.push_back((Edge)
            {
                to,from,0,0
            });//反向弧
            m=edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
    
        bool BFS()
        {
            memset(vis,0,sizeof(vis));
            queue<int>Q;
            Q.push(s);
            d[s]=0;
            vis[s]=1;
            while(!Q.empty())
            {
                int x=Q.front();
                Q.pop();
                for (int i=0; i<G[x].size() ; i++)
                {
                    Edge& e=edges[G[x][i]];
                    if(!vis[e.to]&&e.cap>e.flow)
                    {
                        vis[e.to]=1;
                        d[e.to]=d[x]+1;
                        Q.push(e.to);
                    }
                }
            }
            return vis[t];
        }
    
        int DFS(int x,int a)//x为当前节点,a为目前为止所有弧的最小流量
        {
            if(x==t||a==0)return a;
            int flow=0,f;
            for (int& i=cur[x]; i<G[x].size() ; i++ )
            {
                Edge& e = edges[G[x][i]];
                if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)//下一层次加1并且残留量不为零
                {
                    e.flow+=f;
                    edges[G[x][i]^1].flow-=f;
                    flow+=f;
                    a-=f;
                    if(a==0)break;
                }
            }
             return flow;
        }
    
        int Maxflow(int s,int t)
        {
            this->s=s;
            this->t=t;
            int flow=0;
            while(BFS())
            {
                memset(cur,0,sizeof(cur));
                flow+=DFS(s,INF);
            }
            return flow;
        }
    };
    Dinic dc;
    int main()
    {
        int n1,n2,n3,m1,m2,m3;
        scanf("%d %d %d",&n1,&n2,&n3);
        scanf("%d",&m1);
        for(int i=1; i<=m1; i++)//练习册指书的边
        {
            int x,y;
            scanf("%d %d",&x,&y);
            dc.AddEdge(y,x+n2,1);
        }
        scanf("%d",&m2);
        for(int i=1; i<=m2; i++)//书指向答案的边
        {
            int x,y;
            scanf("%d %d",&x,&y);
            dc.AddEdge(x+n2+n1,2*n1+n2+y,1);
        }
        for(int i=1; i<=n2; i++)//建立源点指向练习册的边
        {
            dc.AddEdge(0,i,1);
        }
        for(int i=1; i<=n1; i++)//建立书指向书的边
        {
            dc.AddEdge(n2+i,n2+n1+i,1);
        }
        int end=n1*2+n2+n3+1;
        for(int i=1; i<=n3; i++)//建立书指向终点的边
        {
            dc.AddEdge(n2+2*n1+i,end,1);
        }
        printf("%d",dc.Maxflow(0,end));
        return 0;
    }

    二,建立二分图跑网络流

    题意,给你个二分图,每次选择一条边会给每个点加一个度,问能否使得点的度的范围在[l,r]之间。

    https://nanti.jisuanke.com/t/31447

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int maxn=20010;
    const int N=0x3f3f3f3f;
    const int INF=0x3fffffff;
    int degree[maxn];
    int u[maxn];
    int v[maxn];
    struct Dinic
    {
        struct Edge
        {
            int from,to,cap,flow;
        };
        int n,m,s,t;
        vector<Edge>edges;
        vector<int>G[maxn];
        bool vis[maxn];
        int d[maxn];
        int cur[maxn];
    
        void AddEdge(int from,int to,int cap)
        {
            edges.push_back((Edge)
            {
                from,to,cap,0
            });
            edges.push_back((Edge)
            {
                to,from,0,0
            });//反向弧
            m=edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
    
        bool BFS()
        {
            memset(vis,0,sizeof(vis));
            queue<int>Q;
            Q.push(s);
            d[s]=0;
            vis[s]=1;
            while(!Q.empty())
            {
                int x=Q.front();
                Q.pop();
                for (int i=0; i<G[x].size() ; i++)
                {
                    Edge& e=edges[G[x][i]];
                    if(!vis[e.to]&&e.cap>e.flow)
                    {
                        vis[e.to]=1;
                        d[e.to]=d[x]+1;
                        Q.push(e.to);
                    }
                }
            }
            return vis[t];
        }
    
        int DFS(int x,int a)//x为当前节点,a为目前为止所有弧的最小流量
        {
            if(x==t||a==0)return a;
            int flow=0,f;
            for (int& i=cur[x]; i<G[x].size() ; i++ )
            {
                Edge& e = edges[G[x][i]];
                if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)//下一层次加1并且残留量不为零
                {
                    e.flow+=f;
                    edges[G[x][i]^1].flow-=f;
                    flow+=f;
                    a-=f;
                    if(a==0)break;
                }
            }
            return flow;
        }
    
        int Maxflow(int s,int t)
        {
            this->s=s;
            this->t=t;
            int flow=0;
            while(BFS())
            {
                memset(cur,0,sizeof(cur));
                flow+=DFS(s,INF);
            }
            return flow;
        }
    };
    
    void init()
    {
        memset(degree,0,sizeof(degree));
        return;
    }
    int main()
    {
        int cas,i,l,r,minn,maxx,res,sum,n,m,k;
        cas=1;
        while(scanf("%d%d%d",&n,&m,&k)!=EOF)
        {
            init();
            scanf("%d%d",&l,&r);
            for(i=1; i<=k; i++)
            {
                scanf("%d%d",&u[i],&v[i]);
                v[i]+=n;
                degree[u[i]]++,degree[v[i]]++;
            }
            minn=N,maxx=0;
            for(i=1; i<=n+m; i++)
            {
                minn=min(minn,degree[i]);
                maxx=max(maxx,degree[i]);
            }
            if(l<=minn)
            {
                if(maxx<=r) printf("Case %d: Yes
    ",cas++);
                else
                {
    
                    for(i=1; i<=k; i++)
                    {
                        if(degree[u[i]]>r&&degree[v[i]]>r)
                        {
                            degree[u[i]]--,degree[v[i]]--;
                        }
                    }
                    int source=0,sink=n+m+1;
                    Dinic dc;
                    for(i=1; i<=k; i++)
                    {
                        if(degree[u[i]]>r&&degree[v[i]]>l) dc.AddEdge(u[i],v[i],1);
                        else if(degree[v[i]]>r&&degree[u[i]]>l) dc.AddEdge(v[i],u[i],1);
                    }
                    sum=0;
                    for(i=1; i<=n+m; i++)
                    {
                        if(degree[i]>r)
                        {
                            dc.AddEdge(source,i,degree[i]-r);
                            sum+=(degree[i]-r);
                        }
                        else if(degree[i]>l)
                        {
                            dc.AddEdge(i,sink,degree[i]-l);
                        }
                    }
                    res=dc.Maxflow(source,sink);
                    if(res==sum) printf("Case %d: Yes
    ",cas++);
                    else printf("Case %d: No
    ",cas++);
                }
            }
            else printf("Case %d: No
    ",cas++);
        }
        return 0;
    }
    

      

    三,无源上下界网络流问题

    模板题

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1314

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=100005;
    const int INF=0x3fffffff;
    struct Dinic
    {
        struct Edge
        {
            int from,to,cap,flow;
        };
        int n,m,s,t;
        vector<Edge>edges;
        vector<int>G[maxn];
        bool vis[maxn];
        int d[maxn];
        int cur[maxn];
    
        void init(int n)
        {
            for (int i=0; i<=n+1 ; i++ )
                G[i].clear();
            edges.clear();
        }
    
        void AddEdge(int from,int to,int cap)
        {
            edges.push_back((Edge)
            {
                from,to,cap,0
            });
            edges.push_back((Edge)
            {
                to,from,0,0
            });//反向弧
            m=edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
    
        bool BFS()
        {
            memset(vis,0,sizeof(vis));
            queue<int>Q;
            Q.push(s);
            d[s]=0;
            vis[s]=1;
            while(!Q.empty())
            {
                int x=Q.front();
                Q.pop();
                for (int i=0; i<G[x].size() ; i++)
                {
                    Edge& e=edges[G[x][i]];
                    if(!vis[e.to]&&e.cap>e.flow)
                    {
                        vis[e.to]=1;
                        d[e.to]=d[x]+1;
                        Q.push(e.to);
                    }
                }
            }
            return vis[t];
        }
    
        int DFS(int x,int a)//x为当前节点,a为目前为止所有弧的最小流量
        {
            if(x==t||a==0)return a;
            int flow=0,f;
            for (int& i=cur[x]; i<G[x].size() ; i++ )
            {
                Edge& e = edges[G[x][i]];
                if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)//下一层次加1并且残留量不为零
                {
                    e.flow+=f;
                    edges[G[x][i]^1].flow-=f;
                    flow+=f;
                    a-=f;
                    if(a==0)break;
                }
            }
            return flow;
        }
    
        int Maxflow(int s,int t)
        {
            this->s=s;
            this->t=t;
            int flow=0;
            while(BFS())
            {
                memset(cur,0,sizeof(cur));
                flow+=DFS(s,INF);
            }
            return flow;
        }
    };
    int d[maxn];
    int l[maxn];
    Dinic dc;
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            int n,m;
            scanf("%d%d",&n,&m);
            dc.init(n);
            memset(d,0,sizeof d);
            for (int i=0; i<m ; i++ )
            {
                int u,v,low,up;
                scanf("%d%d%d%d",&u,&v,&low,&up);
                d[u]+=low;
                d[v]-=low;
                l[i]=low;
                dc.AddEdge(u,v,up-low);
            }
            int ss=0;
            for (int i=1; i<=n ; i++ )
            {
                if(d[i]>0)
                {
                    dc.AddEdge(i,n+1,d[i]);
                    ss+=d[i];
                }
                else
                    dc.AddEdge(0,i,-d[i]);
            }
            if(dc.Maxflow(0,n+1)==ss)
            {
                cout<<"YES"<<endl;
                for (int i=0; i<m ; i++ )
                {
                    cout<<dc.edges[2*i].flow+l[i]<<endl;
                }
            }
            else
                cout<<"NO"<<endl;
        }
        return 0;
    }
    

      

    四,二分图,建立源点的有源上下界网络流

    题目和上面的二分图一样,解决方法是建立一个源点连向左图,每条边的范围要是[l,r],右图连向汇点,范围一样,左图与右图的边的范围是[0,1],就转化为上面的模板题了。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=100005;
    const int INF=0x3fffffff;
    struct Dinic
    {
        struct Edge
        {
            int from,to,cap,flow;
        };
        int n,m,s,t;
        vector<Edge>edges;
        vector<int>G[maxn];
        bool vis[maxn];
        int d[maxn];
        int cur[maxn];
    
        void init(int n)
        {
            for (int i=0; i<=maxn ; i++ )
                G[i].clear();
            edges.clear();
        }
    
        void AddEdge(int from,int to,int cap)
        {
            edges.push_back((Edge)
            {
                from,to,cap,0
            });
            edges.push_back((Edge)
            {
                to,from,0,0
            });//反向弧
            m=edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
    
        bool BFS()
        {
            memset(vis,0,sizeof(vis));
            queue<int>Q;
            Q.push(s);
            d[s]=0;
            vis[s]=1;
            while(!Q.empty())
            {
                int x=Q.front();
                Q.pop();
                for (int i=0; i<G[x].size() ; i++)
                {
                    Edge& e=edges[G[x][i]];
                    if(!vis[e.to]&&e.cap>e.flow)
                    {
                        vis[e.to]=1;
                        d[e.to]=d[x]+1;
                        Q.push(e.to);
                    }
                }
            }
            return vis[t];
        }
    
        int DFS(int x,int a)//x为当前节点,a为目前为止所有弧的最小流量
        {
            if(x==t||a==0)return a;
            int flow=0,f;
            for (int& i=cur[x]; i<G[x].size() ; i++ )
            {
                Edge& e = edges[G[x][i]];
                if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)//下一层次加1并且残留量不为零
                {
                    e.flow+=f;
                    edges[G[x][i]^1].flow-=f;
                    flow+=f;
                    a-=f;
                    if(a==0)break;
                }
            }
            return flow;
        }
    
        int Maxflow(int s,int t)
        {
            this->s=s;
            this->t=t;
            int flow=0;
            while(BFS())
            {
                memset(cur,0,sizeof(cur));
                flow+=DFS(s,INF);
            }
            return flow;
        }
    };
    int d[maxn];
    int l[maxn];
    Dinic dc;
    int main()
    {
        int n,m,k;
        int acm=1;
        while(~scanf("%d%d%d",&n,&m,&k))
        {
            dc.init(n);
            int l,r;
            scanf("%d%d",&l,&r);
            memset(d,0,sizeof d);
             for(int i=1; i<=n; i++)
            {
                dc.AddEdge(0,n,r-l);
                d[0]+=l;
                d[i]-=l;
            }
            for(int i=1; i<=k; i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                dc.AddEdge(u,v+n,1);
            }
            for(int i=n+1; i<=n+m; i++)
            {
                dc.AddEdge(i,n+m+1,r-l);
                d[i]+=l;
                d[n+m+1]-=l;
            }
            int ss=0;
            for (int i=0; i<=m+n+1 ; i++ )
            {
                if(d[i]>0)
                {
                    dc.AddEdge(i,n+m+3,d[i]);
                    ss+=d[i];
                }
                else
                    dc.AddEdge(n+m+2,i,-d[i]);
            }
            dc.AddEdge(n+m+1,0,0x3fffffff);
            if(dc.Maxflow(n+m+2,n+m+3)==ss)
            {
                printf("Case %d: Yes
    ",acm++);
            }
            else
                printf("Case %d: No
    ",acm++);
    
        }
        return 0;
    }
    

      

  • 相关阅读:
    php curl getinfo
    php 实现树形结构
    E时代主机,其实做一个小虚拟主机还是不错的
    php 生成验证码
    php curl
    nodejs 操作mysql
    php ++a和a++
    nodejs上传图片并显示的例子
    json
    Rock,Paper,Scissors 水NOJ 1090
  • 原文地址:https://www.cnblogs.com/Json-Five/p/9748953.html
Copyright © 2011-2022 走看看