题意:给定n个采购商所需要的k种货物,m个供应商提供的k种货物,对每种货物,从供应商运到采购商所需要的单位路费,求最小总费用。
解法:构图:采购商与源点构边,容量为对应货物该采购商的需求量,费用为0。
采购商与供应商构边,容量为对应货物该采购商的需求量,费用为对应货物从供应商运到采购商所需要的单位路费。
供应商与汇点构边,容量为供应商对该货物的供应量,费用为0。
对每种货物求最小费用最大流,最后相加即可。
若每种货物供应量小于需求量,则输出-1。
解法:构图:采购商与源点构边,容量为对应货物该采购商的需求量,费用为0。
采购商与供应商构边,容量为对应货物该采购商的需求量,费用为对应货物从供应商运到采购商所需要的单位路费。
供应商与汇点构边,容量为供应商对该货物的供应量,费用为0。
对每种货物求最小费用最大流,最后相加即可。
若每种货物供应量小于需求量,则输出-1。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<climits>
using namespace std;
const int MAX=55;
int need[MAX][MAX],provide[MAX][MAX],cap[MAX<<1][MAX<<1],cost[MAX<<1][MAX<<1],a[MAX],b[MAX];
bool inque[MAX<<1];
int que[MAX*MAX],f,r;
int dis[MAX<<1],pre[MAX<<1];
/*
求最小费用路,并更新权值。
*/
int spfa(int st,int ed)
{
memset(inque,false,sizeof(inque));
inque[st]=true;
f=0;
r=1;
que[f]=st;
for(int i=0; i<=ed; i++)
{
dis[i]=INT_MAX;
pre[i]=-1;
}
dis[st]=0;
while(f<r)
{
int fro=que[f++];
inque[fro]=false;
for(int i=1; i<=ed; i++)
if(cap[fro][i]>0&&dis[fro]+cost[fro][i]<dis[i])
{
dis[i]=dis[fro]+cost[fro][i];
pre[i]=fro;
if(!inque[i])
{
que[r++]=i;
inque[i]=true;
}
}
}
if(dis[ed]==INT_MAX)
return -1;
int minflow=INT_MAX;
for(int i=ed; pre[i]!=-1; i=pre[i])
if(cap[pre[i]][i]<minflow)
minflow=cap[pre[i]][i];
for(int i=ed; pre[i]!=-1; i=pre[i])
{
cap[pre[i]][i]-=minflow;
cap[i][pre[i]]+=minflow;
}
return dis[ed]*minflow;
}
/*
除了采购商与源点构边,采购商与供应商构边,供应商与汇点构边外,还需注意其他间接点默认相连的边容量清零!!!
*/
int main()
{
int n,m,k,i,j,mincost;
bool flag;
//freopen("in.txt","r",stdin);
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
if(!n&&!m&&!k)
break;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
flag=true;
for(i=1; i<=n; i++)
for(j=1; j<=k; j++)
{
scanf("%d",&need[i][j]);
a[j]+=need[i][j];
}
for(i=1; i<=m; i++)
for(j=1; j<=k; j++)
{
scanf("%d",&provide[i][j]);
b[j]+=provide[i][j];
}
//判断是否供过于求
for(i=1; i<=k&&flag; i++)
if(a[i]>b[i])
{
flag=false;
}
int kind=k;
mincost=0;
while(k--)
{
memset(cap,0,sizeof(cap));
//采购商与供应商构边
for(i=1; i<=n; i++)
for(j=n+1; j<=n+m; j++)
{
scanf("%d",&cost[i][j]);
if(!flag)
continue;
cost[j][i]=-cost[i][j];
cap[i][j]=need[i][kind-k];
}
if(!flag)
continue;
int st=0,ed=n+m+1;
//采购商与源点构边
for(i=1; i<=n; i++)
{
cost[st][i]=cost[i][st]=0;
cap[st][i]=need[i][kind-k];
}
//供应商与汇点构边
for(i=n+1; i<=n+m; i++)
{
cost[ed][i]=cost[i][ed]=0;
cap[i][ed]=provide[i-n][kind-k];
}
int tmp;
while((tmp=spfa(st,ed))!=-1)
mincost+=tmp;
}
if(!flag)
mincost=-1;
printf("%d\n",mincost);
}
return 0;
}