zoukankan      html  css  js  c++  java
  • 训练指南 网络流题集


    layout: post
    title: 训练指南 网络流题集
    author: "luowentaoaa"
    catalog: true
    mathjax: true
    tags:
    - 网络流
    - 图论
    - 训练指南


    A.UVA - 11248 (最大流,最小割)

    UVA - 11248 Frequency Hopping

    题意

    给定一个有向网络,每条边均有一个容量。问是否存在一个从点1到点N,流量为C的流。如果不存在,是否可以恰好修改一条弧的容量,使得存在这样的流。

    思路

    先求一遍最大流,如果大于等于C,那么就直接输出possible。

    否则的话就是最大流达不到C,那么对哪些边进行扩容呢,肯定是选择最小割!

    将最小割的边集全部求出来,之后每条边都尝试将容量变为C,看看能否达到要求。

    优化一:求完最大流后把流量留着,以后每次在它的基础上增广。

    优化二:每次没必要求出最大流,增广到流量至少为C时就可以停下来。

    搞不到为什么刘汝佳代码那么快

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=998244353;
    const int maxn=1e6+50;
    const ll inf=0x3f3f3f3f3f3f3f3fLL;
    struct Edge{
        int from,to,cap,flow;
        Edge(int u,int v,int c,int f)
        :from(u),to(v),cap(c),flow(f){}
        bool operator<(const Edge& a)const{
            return from<a.from||(from==a.from&&to<a.to);
        }
    };
    struct Dinic{
        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){
            this->n=n;
            for(int i=0;i<n;i++)G[i].clear();
            edges.clear();
        }
        void ClearFlow(){
            for(int i=0;i<edges.size();i++)edges[i].flow=0;
        }
        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));
            memset(d,0,sizeof(d));
            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){
            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){
                    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;
        }
        vector<int>Mincut(){ /// call this after maxflow
            vector<int>ans;
            for(int i=0;i<edges.size();i++){
                Edge& e=edges[i];
                if(vis[e.from]&&!vis[e.to]&&e.cap>0)ans.push_back(i);
            }
            return ans;
        }
        void Reduce(){
            for(int i=0;i<edges.size();i++)edges[i].cap-=edges[i].flow;
        }
    }g;
    
    int main()
    {
        int n,e,c,kase=0;
        while(scanf("%d%d%d",&n,&e,&c)==3&&n){
            g.init(n);
            while(e--){
                int a,b,c;
                scanf("%d%d%d",&a,&b,&c);
                g.AddEdge(a-1,b-1,c);
            }
            int flow=g.Maxflow(0,n-1);
            printf("Case %d: ",++kase);
            if(flow>=c)printf("possible
    ");
            else{
                vector<int>cut=g.Mincut();
                g.Reduce();
                vector<Edge>ans;
                for(int i=0;i<cut.size();i++){
                    Edge& e=g.edges[cut[i]];
                    e.cap=c;
                    g.ClearFlow();
                    if(flow+g.Maxflow(0,n-1)>=c)ans.push_back(e);
                    e.cap=0;
                }
                if(ans.empty())printf("not possible
    ");
                else{
                    sort(ans.begin(),ans.end());
                    printf("possible option:(%d,%d)", ans[0].from+1, ans[0].to+1);
                    for(int i = 1; i < ans.size(); i++)
                    printf(",(%d,%d)", ans[i].from+1, ans[i].to+1);
                    printf("
    ");
                }
            }
        }
        return 0;
    }
    

    B.UVALive - 2531 (构图最大流)

    题意

    有 n 个队伍进行比赛,每个队伍比赛数目是一样的,每场恰好一个胜一个负,给定每个队伍当前胜的场数败的数目,以及两个队伍剩下的比赛场数,问你冠军队伍可能是哪些队。

    思路

    对每个队伍 i 进行判断是不是能冠军,最优的情况的就是剩下的比赛全都胜,也就是一共胜的数目就是剩下的要比赛的数再加上原来胜的数目sum,然后把每两个队伍比赛看成一个结点,(u, v),然后从 s 向 结点加一条容量要打的比赛数目的容量,然后从 (u, v) 向 u 和 v 分别加一条容量为无穷大的边,然后每个 u 向 t 加一条容量为 sum - w[i] ,跑一个最大流,如果是满流是,那么就是有解,也就是 i 可能是冠军。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=998244353;
    const int maxn=700+50;
    const ll inf=0x3f3f3f3f3f3f3f3fLL;
    struct Edge{
        int from,to,cap,flow;
        Edge(int u,int v,int c,int f)
        :from(u),to(v),cap(c),flow(f){}
        bool operator<(const Edge& a)const{
            return from<a.from||(from==a.from&&to<a.to);
        }
    };
    struct Dinic{
        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){
            this->n=n;
            for(int i=0;i<n;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));
            memset(d,0,sizeof(d));
            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){
            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){
                    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;
        }
    }g;
    const int maxt=25+5;
    int n,w[maxt],d[maxt],a[maxt][maxt];
    inline int ID(int u,int v){return u*n+v+1;}
    inline int ID(int u){return n*n+u+1;}
    bool canWin(int team){
        int total=w[team];
        for(int i=0;i<n;i++)total+=a[team][i];
        for(int i=0;i<n;i++)
            if(w[i]>total)return false;
        g.init(n*n+n+2);
        int full=0;
        int s=0,t=n*n+n+1;
        for(int u=0;u<n;u++){
            for(int v=u+1;v<n;v++){
                if(a[u][v]>0)g.AddEdge(s,ID(u,v),a[u][v]);
                full+=a[u][v];
                g.AddEdge(ID(u,v),ID(u),inf);
                g.AddEdge(ID(u,v),ID(v),inf);
            }
            if(w[u]<total)g.AddEdge(ID(u),t,total-w[u]);
        }
        return g.Maxflow(s,t)==full;
    }
    int main()
    {
        int t;
        cin>>t;
        while(t--){
            cin>>n;
            for(int i=0;i<n;i++)cin>>w[i]>>d[i];
            for(int i=0;i<n;i++)
                for(int j=0;j<n;j++)cin>>a[i][j];
            bool first=true;
            for(int i=0;i<n;i++)
            if(canWin(i)){
                if(first)first=false;else cout<<" ";
                cout<<i+1;
            }
            cout<<endl;
        }
        return 0;
    }
    
    

    C.UVA - 10779 (构图最大流)

    题意

    Bob与他的朋友交换贴纸;他的这些朋友只交换自己没有的贴纸;且用的是自己所有的重复贴纸;现在要求Bob最大能得到多少张贴纸; (Bob可以不只用重复的贴纸)

    思路

    把人和物品都进行编号,添加原点s和汇点e,s到每个物品连边容量为Bob拥有的数目;所有物品向汇点e连边容量为1;

    如果一个人向他拥有的物品连边,容量为数目减1,表示他自己会留一个;如果他不拥有某件物品,则物品向这个人连一条边,表示这个人最多接受一件这个物品;

    然后跑一遍最大流就是答案了;

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=998244353;
    const int maxn=700+50;
    const ll inf=0x3f3f3f3f3f3f3f3fLL;
    struct Edge{
        int from,to,cap,flow;
        Edge(int u,int v,int c,int f)
        :from(u),to(v),cap(c),flow(f){}
        bool operator<(const Edge& a)const{
            return from<a.from||(from==a.from&&to<a.to);
        }
    };
    struct Dinic{
        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){
            this->n=n;
            for(int i=0;i<n;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));
            memset(d,0,sizeof(d));
            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){
            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){
                    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;
        }
    }g;
    const int maxt=30+5;
    int n,w[maxt],d[maxt],a[maxt][maxt],m;
    inline int ID(int u){return u;}///物品
    inline int PID(int u){return m+u;}
    int S,T;
    void build(){
        for(int i=1;i<=m;i++){
            if(a[1][i])
                g.AddEdge(S,i,a[1][i]);
        }
        for(int i=2;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i][j]>=2){
                    g.AddEdge(PID(i),ID(j),a[i][j]-1);
                }
                else if(!a[i][j]){
                    g.AddEdge(ID(j),PID(i),1);
                }
            }
        }
        for(int i=1;i<=m;i++){
            g.AddEdge(ID(i),T,1);
        }
    }
    int main()
    {
        int t;
        int cast=1;
        cin>>t;
        while(t--){
            cin>>n>>m;
            g.init(n+m+2);
            memset(a,0,sizeof(a));
            for(int i=1;i<=n;i++){
                int tot;cin>>tot;
                while(tot--){
                    int aa;
                    cin>>aa;
                    a[i][aa]++;
                }
            }
            S=0,T=n+m+1;
            build();
            cout<<"Case #"<<cast++<<": ";
            cout<<g.Maxflow(S,T)<<endl;
        }
        return 0;
    }
    

    D.UVA - 11613 (最大费用流)

    题意

    A公司生产一种元素,给出该元素在未来M个月中每个月的单位售价,最大生产量,生产成本,最大销售量和最大存储时间,和每月存储代价,问这家公司在M个月内所能赚大的最大利润

    思路

    建边的时候,费用我用的是相反数,所以得到最小费用后要去相反数
    MCMF的时候,用一个数组纪录了到达汇点时所花费的最小价值,因为取的是相反数,所以当价值为正时,就表示已经亏本了,所以可以退出了

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=998244353;
    const int maxn=700+50;
    const ll inf=0x3f3f3f3f3f3f3f3fLL;
    struct Edge{
        int from,to,cap,flow,cost;
        Edge(int u,int v,int c,int f,int w)
        :from(u),to(v),cap(c),flow(f),cost(w){}
    };
    struct MCMF{
        int n,m;
        vector<Edge>edges;
        vector<int>G[maxn];
        int inq[maxn];
        int d[maxn];
        int p[maxn];
        int a[maxn];
        void init(int n){
            this->n=n;
            for(int i=0;i<n;i++)G[i].clear();
            edges.clear();
        }
        void AddEdge(int from,int to,int cap,int cost){
            edges.emplace_back(from,to,cap,0,cost);
            edges.emplace_back(to,from,0,0,-cost);
            m=edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
        bool BellmanFord(int s,int t,int& flow,ll& cost){
            for(int i=0;i<n;i++)d[i]=inf;
            memset(inq,0,sizeof(inq));
            d[s]=0;
            inq[s]=1;
            p[s]=0;
            a[s]=inf;
            queue<int>q;
            q.push(s);
            while(!q.empty()){
                int u=q.front();
                q.pop();
                inq[u]=0;
                for(int i=0;i<G[u].size();i++){
                    Edge& e=edges[G[u][i]];
                    if(e.cap>e.flow&&d[e.to]>d[u]+e.cost){
                        d[e.to]=d[u]+e.cost;
                        p[e.to]=G[u][i];
                        a[e.to]=min(a[u],e.cap-e.flow);
                        if(!inq[e.to]){
                            q.push(e.to);
                            inq[e.to]=1;
                        }
                    }
                }
            }
            if(d[t]>0)return false;
            flow+=a[t];
            cost+=(ll)d[t]*(ll)a[t];
            for(int u=t;u!=s;u=edges[p[u]].from){
                edges[p[u]].flow+=a[t];
                edges[p[u]^1].flow-=a[t];
            }
            return true;
        }
        int MincostMaxflow(int s,int t,ll& cost){
            int flow=0;
            cost=0;
            while(BellmanFord(s,t,flow,cost));
            return flow;
        }
    }g;
    
    int main()
    {
        int t;
        int cast=1;
        cin>>t;
        int month,st_cost;
        while(t--){
            cin>>month>>st_cost;
            g.init(month*2+2);
            int source=0,sink=2*month+1;
            for(int i=1;i<=month;i++){
                int make_cost,make_limit,price,sell_limit,max_store;
                cin>>make_cost>>make_limit>>price>>sell_limit>>max_store;
                g.AddEdge(source,i,make_limit,make_cost);
                g.AddEdge(month+i,sink,sell_limit,-price);
                for(int j=0;j<=max_store;j++){
                    if(i+j<=month)
                        g.AddEdge(i,month+i+j,inf,st_cost*j);
                }
            }
            ll cost=0;g.MincostMaxflow(source,sink,cost);
            cout<<"Case "<<cast++<<": "<<-cost<<endl;
        }
        return 0;
    }
    
    
  • 相关阅读:
    excel批量导入后 数据库校验存储过程
    编译内核时覆盖KBUILD_BUILD_USER和KBUILD_BUILD_HOST
    EDID真实数据块,请参考标准文档仔细核对
    RK30SDK开发板驱动分析(二):DDR频率配置
    Linux中的固件加载例子
    Android中如何禁止音量调节至静音
    C++中内部类访问外部类的私有成员
    DSD, DFF, DSF, DST概念解析
    Android中播放DSD音乐
    Linux系统调用分析
  • 原文地址:https://www.cnblogs.com/luowentao/p/10353862.html
Copyright © 2011-2022 走看看