题目链接:
题意:
Dearboy 是一个优秀的食品供应商,他现在面临一个大问题,需要你的帮忙。在他的销售地区,有N 个店主(编号从1~N)帮他销售食品。Dearboy 有M 仓库(编号从1~M),每个仓库第6 章 网络流问题可以提供K 种不同的食品(编号从1~K)。一旦有店主向他订食品,Dearboy 应该安排哪个仓库、向该店主提供多少食品,以减少总的运输费用?
现已知道,从不同的仓库向不同的店主运输不同种类的单位重量食品所需的费用是不同的。给定每个仓库K 种食品格子的储藏量,N 个店主对K 种食品的订量,以及从不同的仓库运输不同种食品到不同的店主的所需费用,你的任务是安排每个仓库的各种食品供应量,以减少总的运输费用。
解题思路:
题目中有 需求数量(容量) , 运输费用(费用) 很容易想到最小费用最大流
但是 题目还给出了一个K 表示品种数量,同时每个品种的需求数量,运输费用各不相同;也就是说如果要构建网络,每条边要抽象为k条边,每条边表示一种费用.orz
重新浏览题目,注意到 题目给出的k很大(50) ,但给出的点很少(50+50+2),
这样我们就可以针对每一个品种,建一次图,跑一次最小最小费用最大流即可.
最后将所有品种的最小费用加起来即可.
考虑答案为-1的情况:仅当某类产品供不应求时才会出现 , 因为给出的k个费用矩阵是全部有值的.
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 205
#define INF 0x3f3f3f3f
using namespace std;
struct node
{
int to,c,f,w,next;
} edge[maxn*maxn];
int head[maxn],ss;
int supply[55],need[55];
int a[55][55],b[55][55];
int cost[55][55][55];
int dis[maxn],vis[maxn],pre[maxn];
int n,m,k,s,t;
void init()
{
memset(head,-1,sizeof(head));
ss=0;
}
void addedge(int a,int b,int c,int d)
{
edge[ss]=(node){b,c,0,d,head[a]};
head[a]=ss++;
edge[ss]=(node){a,c,c,-d,head[b]};
head[b]=ss++;
}
int spfa()
{
int q[maxn*10];
memset(vis,0,sizeof(vis));
memset(dis,INF,sizeof(dis));
int u,v,head1=0,tail=0;
q[tail++]=s;
dis[s]=0;
while(head1<tail)
{
u=q[head1++];
vis[u]=0;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
v=edge[i].to;
if(edge[i].c-edge[i].f>0 && dis[v]>dis[u]+edge[i].w)
{
dis[v]=dis[u]+edge[i].w;
pre[v]=i;
if(!vis[v])
{
vis[v]=1;
q[tail++]=v;
}
}
}
}
if(dis[t]<INF)
return 1;
return 0;
}
int MCMF()
{
int minn;
int sum=0;
while(spfa())
{
minn=INF; //最多能买minn个
for(int i=t; i!=s; i=edge[pre[i]^1].to)
{
if(edge[pre[i]].c-edge[pre[i]].f<minn)
minn=edge[pre[i]].c-edge[pre[i]].f;
}
for(int i=t; i!=s; i=edge[pre[i]^1].to)
{
edge[pre[i]].f+=minn;
edge[pre[i]^1].f-=minn;
}
sum+=minn*dis[t];
}
return sum;
}
void build(int kind)
{
init();
for(int i=1; i<=m; i++)
addedge(s,i,b[i][kind],0);
for(int j=1; j<=n; j++)
addedge(j+m,t,a[j][kind],0);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
addedge(j,m+i,INF,cost[kind][i][j]);
}
int main()
{
// freopen("in.txt","r",stdin);
while(scanf("%d%d%d",&n,&m,&k)&&(n+m+k))
{
s=0,t=n+m+1;
int flag=0,ans=0;
memset(supply,0,sizeof(supply));
memset(need,0,sizeof(need));
for(int i=1; i<=n; i++)
for(int j=1; j<=k; j++)
{
scanf("%d",&a[i][j]);
need[j]+=a[i][j];
}
for(int i=1; i<=m; i++)
for(int j=1; j<=k; j++)
{
scanf("%d",&b[i][j]);
supply[j]+=b[i][j];
}
for(int i=1; i<=k; i++)
if(supply[i]<need[i]) //供不应求
flag=1;
for(int kk=1; kk<=k; kk++)
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
scanf("%d",&cost[kk][i][j]);
if(flag)
{
printf("-1\n");
continue;
}
for(int i=1; i<=k; i++) //建k次图 跑k次最小费用最大流 orz
{
build(i);
ans+=MCMF();
}
printf("%d\n",ans);
}
return 0;
}