网络流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\n%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\n",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\n",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\n%lld",ans2,ans1);
    return 0;
    
}
View Code

 

posted @ 2018-08-10 01:57  1371767389  阅读(225)  评论(0编辑  收藏  举报