POJ 2516 Minimum Cost (KM最优匹配)

题意:有N家家店,每家店都对K种货物有需求;同时有M家仓库,对K钟货物有供应。对于每种货物,每个仓库送至每家店都有自己的单位费用。求满足所有店所有货物的最小费用

分析:对于每一种货物,如果总需求大于总费用,那么无解的;否则可以用KM匹配求解每一种货物的最小费用。

因为KM求的是最优匹配,所以建图的时候,建负权边即可。

将每一份需求和每一份供应都离散化,而不是把一个店的需求和每个一仓库的供应建立边。

#include<stdio.h>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int maxn =305;
const int INF= 1000000;

int w[maxn][maxn];
int m,n;//n左m右 
int cx[maxn],cy[maxn];//顶标 
bool usex[maxn],usey[maxn];//本回合使用的x,y 
int link[maxn];//link[i]=x代表:在y图中的i与x相连 

int A,B;

bool dfs(int u){
    usex[u]=1;
    for(int i=1;i<=B;i++)
        if(!usey[i]&&cx[u]+cy[i]==w[u][i]){
            usey[i]=1;
            if(link[i]==-1||dfs(link[i])){ 
                link[i]=u;
                return 1;   
            }
        }
    return 0;
}
int KM(){
    memset(cy,0,sizeof(cy));
    memset(cx,-1,sizeof(cx));
    memset(link,-1,sizeof(link));
    for(int i=1;i<=A;i++)
        for(int j=1;j<=B;j++)
            cx[i]=max(cx[i],w[i][j]);
    for(int i=1;i<=A;i++){      
        while(1){
            int d=INF;
            memset(usex,0,sizeof(usex));
            memset(usey,0,sizeof(usey));
            if(dfs(i))break;
            for(int i=1;i<=A;i++)
                if(usex[i])
                    for(int j=1;j<=B;j++)
                        if(!usey[j])d=min(d,cx[i]+cy[j]-w[i][j]);
            if(d==INF)return -1;
            for(int i=1;i<=A;i++)
                if(usex[i])cx[i]-=d;
            for(int i=1;i<=B;i++)
                if(usey[i])cy[i]+=d;
        }
    }

    int ans=0;
    for(int i=1;i<=B;i++){
        if(~link[i]){
            ans -= w[link[i]][i];
        }
    }
    return ans;
}

int nd[maxn][maxn];
int sp[maxn][maxn];
int ct[maxn][maxn][maxn];
int cas;

int cnt1[maxn],cnt2[maxn];

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int T,tmp;
    int u,v,k;
    while(scanf("%d%d%d",&n,&m,&k)==3){
        if(!n && !m && !k) break;
        
        for(int i=1;i<=n;++i){
            for(int j=1;j<=k;++j){
                scanf("%d",&nd[i][j]);
            }
        }
        
        for(int i=1;i<=m;++i){
            for(int j=1;j<=k;++j){
                scanf("%d",&sp[i][j]);
            }
        }
        
        for(int i=1;i<=k;++i){
            for(int j=1;j<=n;++j){
                for(int t = 1;t<=m;++t){
                    scanf("%d",&ct[i][j][t]);
                }
            }
        }

        bool flag = true;
        for(int cas=1;cas<=k;++cas){
            int need = 0,supply =0;
            for(int i=1;i<=n;++i)   need += nd[i][cas];
            for(int i=1;i<=m;++i)   supply += sp[i][cas];
            if(need>supply){
                flag = false;
                break;
            }
        }

        if(!flag){
            puts("-1");
            continue;
        }

        int tot = 0;
        for(int cas = 1;cas<=k;++cas){
            A=B=0;
            for(int i=1;i<=n;++i){
                for(int j=1;j<=nd[i][cas];++j){
                    cnt1[++A] = i;      
                }
            }
            for(int i=1;i<=m;++i){
                for(int j=1;j<=sp[i][cas];++j){
                    cnt2[++B] = i;
                }
            }
            for(int i=1;i<=A;++i){
                for(int j=1;j<=B;++j){
                    w[i][j] = -ct[cas][cnt1[i]][cnt2[j]];
                }
            }
            int tmp = KM();
            tot+=tmp;
        }
        printf("%d\n",tot);
    }
    return 0;
}

 

posted @ 2018-08-10 18:56  xiuwenL  阅读(301)  评论(0编辑  收藏  举报