#include "stdio.h" // 最小费用最大流 poj 2516#include "string.h"#include "queue"using namespace std;#define N 115#define INF 1000000000struct node {int u,v,w,k;int next;}edge[8*N*N];int store[N];int n,m,k,ans,idx;int head[N],dis[N],route[N],mark[N];int shop[N][N],supply[N][N],cost[N][N];void init();void EK(int start,int end); int SPFA(int start,int end); void adde(int u,int v,int w,int k); void addedge(int u,int v,int w,int k); int main(){int sum;int i,j,tt;int sum1[N],sum2[N];while(scanf("%d %d %d",&n,&m,&k)){tt=k;if(n==0 && m==0 && k==0)return 0;memset(sum1,0,sizeof(sum1));memset(sum2,0,sizeof(sum2));for(i=1;i<=n;i++){for(j=1;j<=k;j++){scanf("%d",&shop[i][j]);sum1[j]+=shop[i][j]; //N家商店需要第j件物品的总件数}}for(i=1;i<=m;i++){for(j=1;j<=k;j++){scanf("%d",&supply[i][j]);sum2[j]+=supply[i][j]; //M处仓库供应第j件物品的总件数}}sum = 0; //答案初始化(sum记录结果)bool flag=true;for(tt=1;tt<=k;tt++){if(sum1[tt]>sum2[tt]) flag=false;init();int start=0,end=n+m+1;for(i=1;i<=n;i++){for(j=1;j<=m;j++){scanf("%d",&cost[i][j]);adde(j,i+m,cost[i][j],INF);}}for(j=1;j<=m;j++)adde(start,j,0,supply[j][tt]);for(i=1;i<=n;i++){store[i] = idx;adde(i+m,end,0,shop[i][tt]);}while(SPFA(start,end))EK(start,end);sum += ans;}if(flag==false)printf("-1\n");elseprintf("%d\n",sum);}return 0;}void init(){ans = 0;idx = 0;memset(head,-1,sizeof(head));}void adde(int u,int v,int w,int k) //对其中的一条再加上一条流量为0的回路 { addedge(u,v,w,k); addedge(v,u,-w,0); } void addedge(int u,int v,int w,int k) //邻接表建边 { edge[idx].u = u; edge[idx].v = v; edge[idx].w = w; edge[idx].k = k; edge[idx].next = head[u]; head[u] = idx; idx++; } int SPFA(int start,int end) //找一条存在流量的最小费用流(存在流量就行) { int i; memset(mark,false,sizeof(mark)); //初始化标记数组mark[]; memset(route,-1,sizeof(route)); //ruote[]记录流量路径(存下一条边的下标) for(i=start;i<=end;i++) dis[i] = INF; dis[start] = 0; queue<int> q; q.push(start); mark[start] = true; int x,y; while(!q.empty()) { x = q.front(); for(i=head[x];i!=-1;i=edge[i].next) { y = edge[i].v; if(edge[i].k && dis[y] > dis[x] + edge[i].w) { dis[y] = dis[x] + edge[i].w; route[y] = i; //route[]里面存的为边的下标 if(mark[y] == false) { mark[y] = true; q.push(y); } } } q.pop(); mark[x] = false; //对出队列的点的标记还原 } if(dis[end] == INF) return 0; return 1; } void EK(int start,int end) { int s=INF; int x,y; y = route[end];while(y!=-1){if(s>edge[y].k)s = edge[y].k;y = route[edge[y].u];} y = route[end]; while(y!=-1) { x = y^1; //很特别的处理; edge[y].k -= s; //对流量进行处理(正减反加) edge[x].k += s; ans += edge[y].w*s; y = route[edge[y].u]; //通过route[]访问路径上的下一个节点 }}