题意:有N个客户,M个仓库,和K种货物。已知每个客户需要每种货物的数量,每个仓库存储每种货物的数量,每个仓库运输各种货物去各个客户的单位费用。判断所有的仓库能否满足所有客户的需求,如果可以,求出最少的运输总费用。
最小费用最大流。先判断是否每种货物的存储总量都足够,足够的话,对每一种货物进行一次最小费用最大流求出完成这种货物运输的最小总费用,所有的总费用相加就是结果了
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<stack>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=100 ;
const int M=80000 ;
const int inf=1<<30 ;
struct node
{
int u,v,c,cost,next;
}edge[M] ;
int head[N],dist[N],pre[N],pp[N],vist[N];
int need[N][N],stroe[N][N],Need[N],Stroe[N] ;
int top;
void add(int u ,int v,int c,int cost)
{
edge[top].u=u;
edge[top].v=v;
edge[top].c=c;
edge[top].cost=cost;
edge[top].next=head[u];
head[u]=top++;
edge[top].u=v;
edge[top].v=u;
edge[top].c=0;
edge[top].cost=-cost;
edge[top].next=head[v];
head[v]=top++;
}
int SPFA(int s,int t)
{
int u , v ;
memset(vist,0,sizeof(vist));
memset(pre,-1,sizeof(pre));
for(int i = 0 ; i <= t ; i++) dist[i]=inf ;
vist[s]=1;dist[s]=0;pre[s]=s;
queue<int>q;
q.push(s);
while(!q.empty())
{
u=q.front();
q.pop();
vist[u]=0;
for(int i =head[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(edge[i].c && dist[v] > dist[u]+edge[i].cost)
{
dist[v] = dist[u]+edge[i].cost ;
pre[v]=u;
pp[v]=i;
if(!vist[v]);
{
vist[v]=1;
q.push(v);
}
}
}
}
if(dist[t]==inf) return 0;
return 1 ;
}
int MFMC(int s,int t)
{
int mincost=0,flow=0,minflow ;
while(SPFA(s,t))
{
minflow=inf;
for(int i=t;i!=s;i=pre[i])
minflow=min(minflow,edge[pp[i]].c);
for(int i=t;i!=s;i=pre[i])
{
edge[pp[i]].c -= minflow;
edge[pp[i]^1].c += minflow;
}
flow += minflow;
mincost += dist[t]*minflow ;
// printf("****");
}
return mincost ;
}
int main()
{
int n,m,K,k ,w;
while(~scanf("%d%d%d",&n,&m,&K))
{
if( (n+m+K)==0) break;
memset(Need,0,sizeof(Need)) ;
memset(Stroe,0,sizeof(Stroe)) ;
for(int i = 1 ; i <= n ;i++)
for(int j = 1 ; j <=K; j++)
{
scanf("%d",&need[i][j]) ; //i客户需要j货物的数量
Need[j] += need[i][j] ; //客户需要j货物的总数量
}
for(int i = 1 ; i <= m ; i++)
for(int j = 1 ; j <= K; j++)
{
scanf("%d",&stroe[i][j]) ;//i仓库储存j货物的数量
Stroe[j] += stroe[i][j] ; //仓库储存j货物的总数量
}
int flag = 0 ; //判断是否有解
for(int i = 1 ; i <= K ; i++)
if(Need[i] > Stroe[i])//无解
{
flag=1; break;
}
int ans = 0 ,s=0,t=n+m+1;
for(int k = 1 ; k <= K ; k++)//K种物品,K次建图
{
top =0;
memset(head,-1,sizeof(head));
for(int i = 1 ; i <= n ; i++)
for(int j = 1 ; j <= m ; j++)
{
scanf("%d",&w) ; //j仓库到i客户的单位花费
add(j,m+i,inf,w);//连边
}
if(flag) continue ; //无解,不用继续下去
for(int i = 1 ; i <= m ;i++)
add(s,i,stroe[i][k] ,0) ;
for(int i = 1 ; i <= n ; i++)
add(m+i,t,need[i][k],0) ;
ans += MFMC(s,t) ;//对k物品跑一次费用流
}
if(flag) printf("-1\n") ;
else printf("%d\n",ans) ;
}
return 0;
}