POJ 2516 Minimum Cost【最小费用最大流】

题意:有 M 个供应商,N 个店主,K 个物品, 知道了每个供应商对每个物品的供应量,每个店主对每个物品的需求量,和每个供应商把每个物品送到每个店主所需要花的费用,

        问已有的货物是否可以满足所有供应商的需求,如果满足,求出供应所需花费的最小费用。

分析:忘记把反向费用设为正向费用的负值,再次卡了N久 T-T...谨记之...

        由于每个物品互不相关,所以可以分开求费用流,最后把所有物品的费用流加起来即为总的费用流。

        建图: 

        源点 S=0

        汇点 T=N+M+1

        供应商编号 1...M

        店主编号    M+1...M+N

        流量边:  源点到每个供应商的边的容量为物品的供应量;

                     每个供应商和每个店主之间的边的容量为物品的供应量;

                     每个店主到汇点的边的容量为店主对物品的需求量;

        费用边:   每个供应商到每个店主的费用边在正向上等于供应商送相应物品到店主的花费,反向费用为正向费用的负值。

#include<cstdio>
#include<cstring>
#define N 105
#define INF 0x1f1f1f1f
#define min(a,b)(a)<(b)?(a):(b)
#define max(a,b)(a)>(b)?(a):(b)
#define clr(x)memset(x,0,sizeof(x))
int cap[N][N];
int cost[N][N];
int q[100000];
int pre[N];
int dis[N];
int v[N];
int s,t;
int n,m,K;
int spfa()
{
    int i,x,front,rear;
    front=rear=0;
    for(i=0;i<=t;i++)
        dis[i]=INF;
    clr(v);
    q[rear++]=s;
    dis[s]=0;
    v[s]=1;
    while(front<rear)
    {
        x=q[front++];
        v[x]=0;
        for(i=0;i<=t;i++)
            if(cap[x][i]&&dis[i]>dis[x]+cost[x][i])
            {
                dis[i]=dis[x]+cost[x][i];
                pre[i]=x;
                if(!v[i])
                {
                    v[i]=1;
                    if(dis[i]<=dis[x]&&front>0)
                         q[--front]=i;
                    else q[rear++]=i;
                }
            }
    }
    if(dis[t]!=INF)
        return 1;
    return 0;
}
int costflow()
{
    int tot=0;
    int flow=0;
    int u;
    int minf=INF;
    while(spfa())
    {
        for(u=t;u!=s;u=pre[u])
            minf=min(minf,cap[pre[u]][u]);
        for(u=t;u!=s;u=pre[u])
        {
            cap[pre[u]][u]-=minf;
            cap[u][pre[u]]+=minf;
            flow+=cost[pre[u]][u]*minf;
        }
    }
    return flow;
}
int offer[105][105];
int need[105][105];
int check_offer[105];
int check_need[105];
int main()
{
    int i,j,k,res,flag;
    while(scanf("%d%d%d",&n,&m,&K)!=EOF)
    {
        if(n==0&&m==0&&K==0)
            break;
        flag=0;
        s=0;        // 源点
        t=n+m+1;    // 汇点
        clr(check_offer);
        clr(check_need);
        for(i=m+1;i<=m+n;i++)
            for(j=1;j<=K;j++)
            {
                scanf("%d",&need[i][j]);
                check_need[j]+=need[i][j];
            }
        for(i=1;i<=m;i++)
            for(j=1;j<=K;j++)
            {
                scanf("%d",&offer[i][j]);
                check_offer[j]+=offer[i][j];
            }
        for(i=1;i<=K;i++)
            if(check_offer[i]<check_need[i])
            {   
                flag=1;
                break;
            }
        res=0;
        for(k=1;k<=K;k++)
        {
            clr(cap);
            clr(cost);
            for(i=m+1;i<=m+n;i++)
                for(j=1;j<=m;j++)
                {
                    scanf("%d",&cost[j][i]);
                    cost[i][j]=-cost[j][i];
                }
            if(flag)continue;
            for(i=1;i<=m;i++)
                cap[s][i]=offer[i][k];
            for(i=m+1;i<=m+n;i++)
                cap[i][t]=need[i][k];
            for(i=1;i<=m;i++)
                for(j=m+1;j<=m+n;j++)
                    cap[i][j]=offer[i][k];
            res+=costflow();
        }
        if(flag)
            printf("-1\n");
        else
        printf("%d\n",res);
    }
    return 0;
}

 

 

posted @ 2012-07-28 17:46  'wind  阅读(318)  评论(0编辑  收藏  举报