最小权值匹配!所谓最小权值匹配:即将左右两边的点配对,在最大匹配数的情况下,求最小权值!
关键在于建图:将每个店所要求的货物N,拆成N个点,同时supply的地方,所提供的货物n,也拆成n个点。--->套用最小权值匹配。
ps:对此题,最小权值匹配ms比最小费用最大流快!
#include<iostream> #include<cstdio> #include<cstring> #define maxn 55 using namespace std; int n,m,k; int order[maxn][maxn],supply[maxn][maxn],cost[maxn][maxn]; int lx[maxn*3],ly[maxn*3],my[maxn*3],slack[maxn*3]; bool vx[maxn*3],vy[maxn*3]; int topx,topy; int ans; int A[maxn*3],B[maxn*3],W[maxn*3][maxn*3]; bool dfs(int u) { int v,t; vx[u]=1; for(v=1;v<=topy;v++) { if(!vy[v]) { t=W[u][v]-lx[u]-ly[v]; if(t==0) { vy[v]=1; if(my[v]==-1||dfs(my[v])) { my[v]=u;return true; } } else slack[v]=slack[v]<t?slack[v]:t; } } return false; } void KM() { int i,j,min,d; for(i=1;i<=topx;i++) { min=10000; for(j=1;j<=topy;j++) if(W[i][j]<min) min=W[i][j]; lx[i]=min; } memset(ly,0,sizeof(ly)); memset(my,-1,sizeof(my)); for(i=1;i<=topx;i++) { memset(slack,127,sizeof(slack)); while(1) { memset(vx,0,sizeof(vx)); memset(vy,0,sizeof(vy)); if(dfs(i)) break; d=999999; for(j=1;j<=topy;j++) if(!vy[j]) d=d<slack[j]?d:slack[j]; for(j=1;j<=topx;j++) if(vx[j]) lx[j]+=d; for(j=1;j<=topy;j++) if(vy[j]) ly[j]-=d; } } for(i=1;i<=topy;i++) { if(my[i]!=-1) ans+=W[my[i]][i]; } } int main() { int i,j,t; bool flag; while(1) { cin>>n>>m>>k; int require,provide; if(n+m+k==0) break; ans=0; for(i=1;i<=n;i++) { for(j=1;j<=k;j++) cin>>order[i][j]; } for(i=1;i<=m;i++) for(j=1;j<=k;j++) cin>>supply[i][j]; flag=true; for(t=1;t<=k;t++) { for(i=1;i<=n;i++) for(j=1;j<=m;j++) cin>>cost[i][j]; provide=0;require=0; for(i=1;i<=n;i++) require+=order[i][t]; for(i=1;i<=m;i++) provide+=supply[i][t]; if(require>provide) flag=false; if(flag) { topx=0;topy=0; for(i=1;i<=n;i++) for(j=1;j<=order[i][t];j++) { A[++topx]=i; } for(i=1;i<=m;i++) for(j=1;j<=supply[i][t];j++) { B[++topy]=i; } for(i=1;i<=topx;i++) for(j=1;j<=topy;j++) W[i][j]=cost[A[i]][B[j]]; KM(); } } if(flag) cout<<ans<<endl; else cout<<-1<<endl; } return 0; }