POJ 2516 Minimum Cost(最小费用最大流)

来源:互联网 发布:男朋友接吻会硬 知乎 编辑:程序博客网 时间:2024/06/07 09:44

POJ 2516 Minimum Cost(最小费用最大流)

http://poj.org/problem?id=2516

题意:

       给出n个客户对k种商品的需求量,又给出m个仓库对k种物品的存货量以及对k种物品从i仓库到j客户的一个物品的运费价格,让判断是否可以满足客户需求,然后就是如果满足求出最小的运费.

分析:

       首先我们必须判断m个仓库是否有足够的k种商品给n个客户,如果不足,那么明显就是不行的. 下面假设仓库的商品足够的话:

       对于每一种商品我们都算出满足满足顾客需求量的最小运费即可.所以我们对K种商品分开处理如下,假设当前处理第x种商品,建图如下:

       源点s编号0, m个仓库编号1到m, n个顾客编号m+1到m+n, 汇点编号m+n+1.

       从源点s到每个仓库i有边(s, i, 仓库i对商品x的存货量, 0)

       从每个仓库i到顾客j有边(i, j, INF, 仓库i到顾客j的单位X商品的运费)

       从每个顾客j到汇点t有边(j, t, 顾客j对X商品的需求量, 0)

       然后我们求最小费用最大流即可求出N个顾客对第X种商品的最小运费.

AC代码:

#include<cstdio>#include<cstring>#include<queue>#include<algorithm>#include<vector>#define INF 1e9using namespace std;const int maxn=200+10;struct Edge{    int from,to,cap,flow,cost;    Edge(){}    Edge(int f,int t,int c,int fl,int co):from(f),to(t),cap(c),flow(fl),cost(co){}};struct MCMF{    int n,m,s,t;    vector<Edge> edges;    vector<int> G[maxn];    bool inq[maxn];    int d[maxn];    int p[maxn];    int a[maxn];    void init(int n,int s,int t)    {        this->n=n, this->s=s, this->t=t;        edges.clear();        for(int i=0;i<n;++i) G[i].clear();    }    void AddEdge(int from,int to,int cap,int cost)    {        edges.push_back(Edge(from,to,cap,0,cost));        edges.push_back(Edge(to,from,0,0,-cost));        m=edges.size();        G[from].push_back(m-2);        G[to].push_back(m-1);    }    bool BellmanFord(int &flow, int &cost)    {        for(int i=0;i<n;++i) d[i]=INF;        memset(inq,0,sizeof(inq));        d[s]=0, a[s]=INF, inq[s]=true, p[s]=0;        queue<int> Q;        Q.push(s);        while(!Q.empty())        {            int u=Q.front(); Q.pop();            inq[u]=false;            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]=true; }                }            }        }        if(d[t]==INF) return false;        flow +=a[t];        cost +=a[t]*d[t];        int 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;    }    int Min_cost()    {        int flow=0,cost=0;        while(BellmanFord(flow,cost));        return cost;    }}MM;int n,m,k;int need[50+5][50+5];       //need[i][j]表i顾客对j商品的需求量int have[50+5][50+5];       //have[i][j]表i仓库对j商品的提供量int cost[50+5][50+5][50+5]; //cost[x][i][j] 表j仓库到i顾客对x商品的单位运费int main(){    while(scanf("%d%d%d",&n,&m,&k)==3 && n)    {    //n客户数量 m商家数量  k商品种类        int goods[maxn];//货物需求量,用来判断货物是否足够        //对于j种商品需要的数量        int enough=true;//初始货物充足        memset(goods,0,sizeof(goods));        for(int i=1;i<=n;++i)        for(int j=1;j<=k;++j)        {            scanf("%d",&need[i][j]);            goods[j]+= need[i][j];        }        for(int i=1;i<=m;++i)        for(int j=1;j<=k;++j)        {            scanf("%d",&have[i][j]);            goods[j] -=have[i][j];        }        for(int h=1;h<=k;++h)        for(int i=1;i<=n;++i)        for(int j=1;j<=m;++j)            scanf("%d",&cost[h][i][j]);        for(int i=1;i<=k;++i)if(goods[i]>0)//货物不足,不用计算了{enough=false;break;}        if(!enough)//初始货物不足        {            printf("-1\n");            continue;        }        int min_cost=0;        for(int g=1;g<=k;++g)        {            int src=0, dst=n+m+1;            MM.init(n+m+2,src,dst);            for(int i=1;i<=m;++i) MM.AddEdge(src,i,have[i][g],0);            for(int i=1;i<=n;++i) MM.AddEdge(m+i,dst,need[i][g],0);            for(int i=1;i<=m;++i)            for(int j=1;j<=n;++j)            {                MM.AddEdge(i,j+m,INF,cost[g][j][i]);            }            min_cost += MM.Min_cost();        }        printf("%d\n",min_cost);    }    return 0;}