/* 最佳匹配的题,m个仓库供应k种商品给n个商家,m*n条运输代价互异,求满足商家需求下的最小运输费用 显然,如果某种商品的供货量比需求大,肯定是无法达到要求的,所以开始要判别是否可以得到最佳匹配 这个题非常有启发意义,刚开始把k种商品一并考虑,tle了,想来也是,这样X集合中的点为m*k,Y中集合为n*k; 执行最小费用流这个复杂度为O(n^3)的算法在这个题目是不可以行的 考虑到k种商品是相互独立的,所以见k次图,每次图中的点为n+m+2个,这样就可以在时限内出答案了 */ #include <stdio.h> #include <iostream> #include <string.h> #include<queue> #include<cmath> using namespace std; const int M=5010,ME=5000000; const int INF=0x3f3fffff; //****************************** int Head[M],Next[ME],Num[ME],Flow[ME],Cap[ME],Cost[ME],Q[M],InQ[M],Len[M],pre_edge[M]; class MaxFlow { public: void clear() { memset(Head,-1,sizeof(Head)); memset(Flow,0,sizeof(Flow)); } void addedge(int u,int v,int cap,int cost) { Next[top] = Head[u]; Num[top] = v; Cap[top] = cap; Cost[top] = cost; Head[u] = top++; Next[top] = Head[v]; Num[top] = u; Cap[top] = 0; Cost[top] = -cost; Head[v] = top++; } int solve(int s,int t) //返回最终的cost { int cost = 0; while(SPFA(s,t)) { int cur = t,minflow = INF; while(cur != s) { if(minflow > Cap[pre_edge[cur]]-Flow[pre_edge[cur]]) minflow = Cap[pre_edge[cur]]-Flow[pre_edge[cur]]; cur = Num[pre_edge[cur] ^ 1]; } cur = t ; while(cur != s) { Flow[pre_edge[cur]] += minflow; Flow[pre_edge[cur] ^ 1] -= minflow; cost += minflow * Cost[pre_edge[cur]]; cur = Num[pre_edge[cur] ^ 1]; } } return cost; } private: bool SPFA(int s,int t) { fill(Len,Len+M,INF); Len[s]=0; int head = -1,tail = -1,cur; Q[++head] = s; while(head != tail) { ++tail; if(tail >= M) tail = 0 ; cur = Q[tail]; for(int i = Head[cur];i != -1;i = Next[i]) { if(Cap[i]>Flow[i] && Len[Num[i]] > Len[cur] + Cost[i]) { Len[Num[i]] = Len[cur] + Cost[i]; pre_edge[Num[i]] = i; if(!InQ[Num[i]]) { InQ[Num[i]]=true; ++head; if(head >= M) head = 0; Q[head] = Num[i]; } } } InQ[cur]=false; } return Len[t] != INF; } int top; }my; //****************************** int need[55][55],canneed[55]; int suply[55][55],cansuply[55]; int trans[55][55][55]; int main() { int n,m,k; while(scanf("%d%d%d",&n,&m,&k),n+m+k) { memset(canneed,0,sizeof(canneed)); memset(cansuply,0,sizeof(cansuply)); for(int i=1;i<=n;i++) { for(int j=1;j<=k;j++) { scanf("%d",&need[i][j]); canneed[j]+=need[i][j];// 第i个客户j商品的订货量 } } for(int i=1;i<=m;i++) { for(int j=1;j<=k;j++) { scanf("%d",&suply[i][j]); cansuply[j]+=suply[i][j];//第i个仓库提供的j商品的量 } } for(int i=1;i<=k;i++) { for(int j=1;j<=n;j++) { for(int f=1;f<=m;f++) { scanf("%d",&trans[i][j][f]);//把单位商品i从仓库f运到商户j所需的费用 } } } int flag=1; for(int i=1;i<=k;i++) if(cansuply[i]<canneed[i]) { flag=0; break; } if(!flag){puts("-1");continue;} int ans=0; for(int f=1;f<=k;f++) { my.clear(); for(int i=1;i<=m;i++) { my.addedge(0,i,suply[i][f],0); for(int g=1;g<=n;g++) { my.addedge(i,m+g,suply[i][f],trans[f][g][i]); } } for(int i=1;i<=n;i++) { my.addedge(m+i,m+n+1,need[i][f],0); } ans+=my.solve(0,m+n+1); } printf("%d\n",ans); } return 0; }