poj 2516 最小费用最大流

来源:互联网 发布:聚翔网络 编辑:程序博客网 时间:2024/05/01 05:55
题意:给定n个采购商所需要的k种货物,m个供应商提供的k种货物,对每种货物,从供应商运到采购商所需要的单位路费,求最小总费用。
解法:构图:采购商与源点构边,容量为对应货物该采购商的需求量,费用为0。
            采购商与供应商构边,容量为对应货物该采购商的需求量,费用为对应货物从供应商运到采购商所需要的单位路费。
            供应商与汇点构边,容量为供应商对该货物的供应量,费用为0。
      对每种货物求最小费用最大流,最后相加即可。
      若每种货物供应量小于需求量,则输出-1。
#include<iostream>#include<cstdio>#include<cstring>#include<queue>#include<climits>using namespace std;const int MAX=55;int need[MAX][MAX],provide[MAX][MAX],cap[MAX<<1][MAX<<1],cost[MAX<<1][MAX<<1],a[MAX],b[MAX];bool inque[MAX<<1];int que[MAX*MAX],f,r;int dis[MAX<<1],pre[MAX<<1];/*求最小费用路,并更新权值。*/int spfa(int st,int ed){    memset(inque,false,sizeof(inque));    inque[st]=true;    f=0;    r=1;    que[f]=st;    for(int i=0; i<=ed; i++)    {        dis[i]=INT_MAX;        pre[i]=-1;    }    dis[st]=0;    while(f<r)    {        int fro=que[f++];        inque[fro]=false;        for(int i=1; i<=ed; i++)            if(cap[fro][i]>0&&dis[fro]+cost[fro][i]<dis[i])            {                dis[i]=dis[fro]+cost[fro][i];                pre[i]=fro;                if(!inque[i])                {                    que[r++]=i;                    inque[i]=true;                }            }    }    if(dis[ed]==INT_MAX)        return -1;    int minflow=INT_MAX;    for(int i=ed; pre[i]!=-1; i=pre[i])        if(cap[pre[i]][i]<minflow)            minflow=cap[pre[i]][i];    for(int i=ed; pre[i]!=-1; i=pre[i])    {        cap[pre[i]][i]-=minflow;        cap[i][pre[i]]+=minflow;    }    return dis[ed]*minflow;}/*除了采购商与源点构边,采购商与供应商构边,供应商与汇点构边外,还需注意其他间接点默认相连的边容量清零!!!*/int main(){    int n,m,k,i,j,mincost;    bool flag;    //freopen("in.txt","r",stdin);    while(scanf("%d%d%d",&n,&m,&k)!=EOF)    {        if(!n&&!m&&!k)            break;        memset(a,0,sizeof(a));        memset(b,0,sizeof(b));        flag=true;        for(i=1; i<=n; i++)            for(j=1; j<=k; j++)            {                scanf("%d",&need[i][j]);                a[j]+=need[i][j];            }        for(i=1; i<=m; i++)            for(j=1; j<=k; j++)            {                scanf("%d",&provide[i][j]);                b[j]+=provide[i][j];            }        //判断是否供过于求        for(i=1; i<=k&&flag; i++)            if(a[i]>b[i])            {                flag=false;            }        int kind=k;        mincost=0;        while(k--)        {            memset(cap,0,sizeof(cap));            //采购商与供应商构边            for(i=1; i<=n; i++)                for(j=n+1; j<=n+m; j++)                {                    scanf("%d",&cost[i][j]);                    if(!flag)                        continue;                    cost[j][i]=-cost[i][j];                    cap[i][j]=need[i][kind-k];                }            if(!flag)                continue;            int st=0,ed=n+m+1;            //采购商与源点构边            for(i=1; i<=n; i++)            {                cost[st][i]=cost[i][st]=0;                cap[st][i]=need[i][kind-k];            }            //供应商与汇点构边            for(i=n+1; i<=n+m; i++)            {                cost[ed][i]=cost[i][ed]=0;                cap[i][ed]=provide[i-n][kind-k];            }            int tmp;            while((tmp=spfa(st,ed))!=-1)                mincost+=tmp;        }        if(!flag)            mincost=-1;        printf("%d\n",mincost);    }    return 0;}


0 0
原创粉丝点击