首先对于一种商品
如果这种货不足需求就直接输出-1
剩下的就是KM算法
分k次分别计算每种商品的最小权值匹配
代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; int n,m,k,shop[55][55],sup[55][55],cost[55][55][55],edges[200][200],cntA,cntB; int belongA[200],belongB[200],A[200],B[200],visA[200],visB[200],mat[200],d; int dfs(int i) { visA[i]=1; for (int j=1;j<=cntB;j++) if (!visB[j]&&edges[i][j]) { int t=edges[i][j]-A[i]-B[j]; if (!t) { visB[j]=1; if (!mat[j]||dfs(mat[j])) { mat[j]=i; return 1; } } else d=min(d,t); } return 0; } int match() { memset(A,0x3f,sizeof(A)); memset(B,0,sizeof(B)); for (int i=1;i<=cntA;i++) for (int j=1;j<=cntB;j++)A[i]=min(A[i],edges[i][j]); memset(mat,0,sizeof(mat)); for (int i=1;i<=cntA;i++) { while (1) { memset(visA,0,sizeof(visA)); memset(visB,0,sizeof(visB)); d=1e9; if (dfs(i))break; for (int j=1;j<=cntA;j++) if (visA[j]) A[j]+=d; for (int j=1;j<=cntB;j++) if (visB[j]) B[j]-=d; } } int ans=0; for (int i=1;i<=cntB;i++)ans+=edges[mat[i]][i]; return ans; } int main() { while (~scanf("%d%d%d",&n,&m,&k),n+m+k) { for (int i=1;i<=n;i++) for (int j=1;j<=k;j++)scanf("%d",&shop[i][j]); for (int i=1;i<=m;i++) for (int j=1;j<=k;j++)scanf("%d",&sup[i][j]); for (int t=1;t<=k;t++) for (int i=1;i<=n;i++) for (int j=1;j<=m;j++)scanf("%d",&cost[t][i][j]); int flag=1; for (int i=1;i<=k;i++) { int need=0,have=0; for (int j=1;j<=n;j++)need+=shop[j][i]; for (int j=1;j<=m;j++)have+=sup[j][i]; if (need>have) { flag=0; puts("-1"); break; } } if (!flag)continue; int ans=0; for (int t=1;t<=k;t++) { cntA=cntB=0; for (int i=1;i<=n;i++) for (int j=1;j<=shop[i][t];j++)belongA[++cntA]=i; for (int i=1;i<=m;i++) for (int j=1;j<=sup[i][t];j++)belongB[++cntB]=i; for (int i=1;i<=cntA;i++) for (int j=1;j<=cntB;j++) edges[i][j]=cost[t][belongA[i]][belongB[j]]; ans+=match(); } printf("%d ",ans); } return 0; }