白皮书最大流算法连续题

Posted json-five

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了白皮书最大流算法连续题相关的知识,希望对你有一定的参考价值。

一,无源网络流的建模

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;
}

  

以上是关于白皮书最大流算法连续题的主要内容,如果未能解决你的问题,请参考以下文章

算法题:最大连续子数组选择

连续最短路算法(Successive Shortest Path)(最小费用最大流)

JavaScript 算法题:从一个数组中找出总和最大的连续子数组

算法题每日一练---第36天:连续子数组的最大和

按算法刷题路线

P3376 网络流-最大流模板题(Dinic+当前弧优化)