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; }
为了更好的明天