zoukankan      html  css  js  c++  java
  • 网络流24题-运输问题

    运输问题

     时间限制: 2 s
     空间限制: 256000 KB
     
    题目描述 Description
    W 公司有m个仓库和n 个零售商店。第i 个仓库有ai 个单位的货物;第j 个零售商店需要bj个单位的货物。货物供需平衡,即  sum(si)=sum(bj)。从第i 个仓库运送每单位货物到第j 个零售商店的费用为cij 。试设计一个将仓库中所有货物运送到零售商店的运输方案,使总运输费用最少。

    编程任务:
    对于给定的m 个仓库和n 个零售商店间运送货物的费用,计算最优运输方案和最差运输方案。

    输入描述 Input Description
    输入的第1行有2 个正整数m和n,分别表示仓库数和零售商店数。接下来的一行中有m个正整数ai ,1≤i≤m,表示第i个仓库有ai 个单位的货物。再接下来的一行中有n个正整数bj ,1≤j≤n,表示第j个零售商店需要bj 个单位的货物。接下来的m行,每行有n个整数,表示从第i 个仓库运送每单位货物到第j个零售商店的费用cij 。
     
    输出描述 Output Description

    将计算出的最少运输费用和最多运输费用输出

    样例输入 Sample Input

    2 3
    220 280
    170 120 210
    77 39 105
    150 186 122

    样例输出 Sample Output

    48500
    69140


    费用流。建立超级源点和超级汇点,跑最小费用最大流和最大费用最大流。
    最大费用最大流的解法:
    1.把所有费用变成相反数跑一遍最小费用最大流,输出答案的相反数。
    #include<bits/stdc++.h>
    #define N 500
    #define INF LLONG_MAX/2
    
    using namespace std;
    struct Edge
    {
        long long  from,to,flow,cost;
    };
    
    struct MCMF
    {
        vector<Edge> edges;
        vector<long long > G[N];
        long long  inq[N];//是否在队列中
        long long  d[N];//距离
        long long  p[N];//上一条弧
        long long  a[N];//可改进量
    
        void init()//初始化
        {
            for(long long  i=0; i<N; i++)G[i].clear();
            edges.clear();
        }
    
        void addedge(long long  from,long long  to,long long  flow,long long  cost)//加边
        {
            edges.push_back((Edge){from,to,flow,cost});
            edges.push_back((Edge){to,from,0,-cost});
            long long  m=edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
    
        bool SPFA(long long  s,long long  t,long long  &flow,long long  &cost)//寻找最小费用的增广路,使用引用同时修改原flow,cost
        {
            for(long long  i=0; i<N; i++)d[i]=INF,inq[i]=0;
            d[s]=0;
            inq[s]=1;
            p[s]=0;
            a[s]=INF;
            queue<long long > Q;
            Q.push(s);
            while(!Q.empty())
            {
                long long  u=Q.front();
                Q.pop();
                inq[u]=0;
                for(long long  i=0; i<G[u].size(); i++)
                {
                    Edge& e=edges[G[u][i]];
                    if(e.flow>0 && 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.flow);
                        if(!inq[e.to])
                        {
                            inq[e.to]=1;
                            Q.push(e.to);
                        }
                    }
                }
            }
            if(d[t]==INF) return false;//汇点不可达则退出
            flow+=a[t];
            cost+=d[t]*a[t];
            long long  u=t;
            while(u!=s)//更新正向边和反向边
            {
                edges[p[u]].flow-=a[t];
                edges[p[u]^1].flow+=a[t];
                u=edges[p[u]].from;
            }
            return true;
        }
    
    
        long long  MincotMaxflow(long long  s,long long  t,long long  &flow,long long  &cost)
        {
            while(SPFA(s,t,flow,cost));
        }
    };
    
    MCMF mcmf;
    int main()
    {
        int m,n;
        int a[N],b[N];
        int cost[N][N];
        
        scanf("%d %d",&m,&n);
        for(int i=1;i<=m;i++)scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)scanf("%d",&b[i]);
        
        for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
        scanf("%d",&cost[i][j]);
        
        
        mcmf.init();
        int s=0,t=n+m+1;
        for(int i=1;i<=m;i++)mcmf.addedge(s,i,a[i],0);
        for(int i=1;i<=n;i++)mcmf.addedge(m+i,t,b[i],0);
        for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)mcmf.addedge(i,j+m,a[i],cost[i][j]);
        
        long long ans1=0,ans2=0,flow;
        flow=0;
        mcmf.MincotMaxflow(s,t,flow,ans1);
        
        mcmf.init();
        for(int i=1;i<=m;i++)mcmf.addedge(s,i,a[i],0);
        for(int i=1;i<=n;i++)mcmf.addedge(m+i,t,b[i],0);
        for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)mcmf.addedge(i,j+m,a[i],-cost[i][j]);
        flow=0;
        mcmf.MincotMaxflow(s,t,flow,ans2);
        
        
        printf("%lld
    %lld",ans1,-ans2);
        
        return 0;
        
    }
    View Code

    2.初始化spfa时dis数组全从INF改为-INF,松弛的条件从 dis[i]>dis[j]+cost[i,j]改为dis[i]<dis[j]+cost[i,j] 。

    #include<bits/stdc++.h>
    #define N 500
    #define INF LLONG_MAX/2
    
    using namespace std;
    struct Edge
    {
        long long  from,to,flow,cost;
    };
    
    struct MCMF
    {
        vector<Edge> edges;
        vector<long long > G[N];
        long long  inq[N];//是否在队列中
        long long  d[N];//距离
        long long  p[N];//上一条弧
        long long  a[N];//可改进量
    
        void init()//初始化
        {
            for(long long  i=0; i<N; i++)G[i].clear();
            edges.clear();
        }
    
        void addedge(long long  from,long long  to,long long  flow,long long  cost)//加边
        {
            edges.push_back((Edge){from,to,flow,cost});
            edges.push_back((Edge){to,from,0,-cost});
            long long  m=edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
    
        bool SPFA(long long  s,long long  t,long long  &flow,long long  &cost)//寻找最小费用的增广路,使用引用同时修改原flow,cost
        {
            for(long long  i=0; i<N; i++)d[i]=INF,inq[i]=0;
            d[s]=0;
            inq[s]=1;
            p[s]=0;
            a[s]=INF;
            queue<long long > Q;
            Q.push(s);
            while(!Q.empty())
            {
                long long  u=Q.front();
                Q.pop();
                inq[u]=0;
                for(long long  i=0; i<G[u].size(); i++)
                {
                    Edge& e=edges[G[u][i]];
                    if(e.flow>0 && 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.flow);
                        if(!inq[e.to])
                        {
                            inq[e.to]=1;
                            Q.push(e.to);
                        }
                    }
                }
            }
            if(d[t]==INF) return false;//汇点不可达则退出
            flow+=a[t];
            cost+=d[t]*a[t];
            long long  u=t;
            while(u!=s)//更新正向边和反向边
            {
                edges[p[u]].flow-=a[t];
                edges[p[u]^1].flow+=a[t];
                u=edges[p[u]].from;
            }
            return true;
        }
    
    
        long long  MincotMaxflow(long long  s,long long  t,long long  &flow,long long  &cost)
        {
            while(SPFA(s,t,flow,cost));
        }
        
        
        bool SPFA2(long long  s,long long  t,long long  &flow,long long  &cost)//寻找最大费用的增广路,使用引用同时修改原flow,cost
        {
        //    printf("%lld
    ",cost);
        
            
            for(long long  i=0; i<N; i++)d[i]=-INF,inq[i]=0;
            d[s]=0;
            inq[s]=1;
            p[s]=0;
            a[s]=INF;
            queue<long long > Q;
            Q.push(s);
            while(!Q.empty())
            {
                long long  u=Q.front();
                Q.pop();
                inq[u]=0;
                for(long long  i=0; i<G[u].size(); i++)
                {
                    Edge& e=edges[G[u][i]];
                    
                    //printf("%d %d %d
    ",e.flow,d[e.to],e.cost+d[u]);
                    
                    if(e.flow>0 && 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.flow);
                        if(!inq[e.to])
                        {
                            inq[e.to]=1;
                            Q.push(e.to);
                        }
                    }
                }
            }
            if(d[t]==-INF) return false;//汇点不可达则退出
            flow+=a[t];
            cost+=d[t]*a[t];
    
            long long  u=t;
            while(u!=s)//更新正向边和反向边
            {
                edges[p[u]].flow-=a[t];
                edges[p[u]^1].flow+=a[t];
                u=edges[p[u]].from;
            }
            return true;
        }
    
        long long  MaxcotMaxflow(long long  s,long long  t,long long  &flow,long long  &cost)
        {
            while(SPFA2(s,t,flow,cost));
        }
        
    };
    
    MCMF mcmf;
    int main()
    {
        int m,n;
        int a[N],b[N];
        int cost[N][N];
        
        scanf("%d %d",&m,&n);
        for(int i=1;i<=m;i++)scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)scanf("%d",&b[i]);
        
        for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
        scanf("%d",&cost[i][j]);
        
        
        mcmf.init();
        int s=0,t=n+m+1;
        for(int i=1;i<=m;i++)mcmf.addedge(s,i,a[i],0);
        for(int i=1;i<=n;i++)mcmf.addedge(m+i,t,b[i],0);
        for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)mcmf.addedge(i,j+m,a[i],cost[i][j]);
        
        long long ans1=0,ans2=0,flow;
        flow=0;
        mcmf.MaxcotMaxflow(s,t,flow,ans1);
        
        mcmf.init();
        for(int i=1;i<=m;i++)mcmf.addedge(s,i,a[i],0);
        for(int i=1;i<=n;i++)mcmf.addedge(m+i,t,b[i],0);
        for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)mcmf.addedge(i,j+m,a[i],cost[i][j]);
        
        flow=0;
        mcmf.MincotMaxflow(s,t,flow,ans2);
        
        printf("%lld
    %lld",ans2,ans1);
        return 0;
        
    }
    View Code
  • 相关阅读:
    他山之石____集合框架__【List,Set,Map之间的区别】
    集合框架__【泛型】
    集合框架__【Set集合】【HashSet】【TreeSet】
    模式串匹配,KMP算法——HDU1686
    模式串匹配,KMP算法——HDU1711
    网络最大流——POJ
    网络最大流——HDU
    拓扑排序——CodeForces-645D
    二分图染色,二分图匹配——HDU
    二分图匹配,最小点覆盖——POJ
  • 原文地址:https://www.cnblogs.com/tian-luo/p/9452705.html
Copyright © 2011-2022 走看看