最近在看最小费用最大流,找了道题,练了练,还是比较简单的。
题意很明确,有N个店主和M个供应商,有K种商品,每个店主对每个商品的需求量不一样,每个供应商对每个商品的库存量也不同,每种商品有不同的供应商提供给不同的店主,价格也不一样,都已给出,求满足店主所有要求的最小花费。由于各个商品互不干扰,就对每种商品求一次最小费用最大流就行了。建一个源点S = 0, 汇点T = N + M +1
一共有三类边:
1.S到供应商的边 供应商编号1到M,花费为0, 容量为库存的数量
2.供应商到店主的边 店主编号M + 1到M + N,花费为读入,容量为INF
3.店主到T的边 花费为0,容量为读入需要的数量
#include<stdio.h>
#define INF 0xfffffff
int N, M, K, S, T;
int cost[54][54][54]; // cost[k][i][j] 第k种商品从第j个供应商送给第i个店主需要的花费
int have[54][54]; // have[i][k] 第i个供应商拥有第k种商品的数量
int need[54][54]; // need[i][k] 第i个店主需要的第k种商品的数量
int b[104][104]; // b[i][j] 节点i 到 节点j的 距离(商品运输的单位花费)
int f[104][104]; // f[i][j] 边<i, j>的剩余容量
int dis[104]; // dis[i] 保存i节点到源点S 的最小距离
int mark[104]; // 求最短路时的标记数组
int stack[104]; // 用栈 + SPFA 来实现最短路
int pre[104]; // 记录最短路 路径
int Min(int a, int b){
return a < b ? a : b;
}
int Spfa()// 求最短路
{
int i, u, v, top;
for (i = S; i <= T; i++){
dis[i] = INF;
mark[i] = 0;
}
mark[S] = 1;
dis[S] = 0;
top = 0;
stack[++top] = S;
while(top){
u = stack[top--];
mark[u] = 0;
for (v = 0; v <= N + M + 1; v++){
if (f[u][v] && dis[v] > dis[u] + b[u][v]){
dis[v] = dis[u] + b[u][v];
pre[v] = u; // 每一次的更新都需要改变前继节点的指向,无论是否要入栈
if (!mark[v]){
stack[++top] = v;
mark[v] = 1;
}
}
}
}
return dis[T];
}
int MinCostMaxFlow()
{
int i, t, minf, c;
int ans = 0;
int maxFlow = 0;
while((c = Spfa()) != INF){
minf = INF;
t = T;
while(t != S){
minf = Min(minf, f[pre[t]][t]);
t = pre[t];
}
maxFlow += minf;
t = T;
while(t != S){
f[pre[t]][t] -= minf;
f[t][pre[t]] += minf;
b[t][pre[t]] = - b[pre[t]][t];
t = pre[t];
}
ans += c * minf;
}
for (i = 1; i <= N; i++){
if (f[i + M][T]) break;
}
return (i <= N ? 0 : ans);
}
void Read()//读入数据
{
int i, j, k;
for (i = 1; i <= N; i++){
for (j = 1; j <= K; j++){
scanf("%d", &need[i][j]);
}
}
for (i = 1; i <= M; i++){
for (j = 1; j <= K; j++){
scanf("%d", &have[i][j]);
}
}
for (k = 1; k <= K; k++){
for (i = 1; i <= N; i++){
for (j = 1; j <= M; j++){
scanf("%d", &cost[k][i][j]);
}
}
}
}
void CreatGraph(int k) // 建图
{
int i, j;
for (i = S; i <= T; i++){
for (j = S; j <= T; j++){
b[i][j] = INF;
f[i][j] = 0;
}
}
for (i = 1; i <= M; i++){
b[S][i] = 0;
// b[i][S] = INF;
f[S][i] = have[i][k];
// f[i][S] = 0;
for (j = 1; j <= N; j++){
b[i][j + M] = cost[k][j][i];
// b[j + M][i] = INF;
f[i][j + M] = INF;
// f[j + M][i] = 0;
}
}
for (i = 1; i <= N; i++){
b[i + M][T] = 0;
// b[T][i + M] = INF;
f[i + M][T] = need[i][k];
// f[T][i + M] = 0;
}
}
int main()
{
int k, t, ans;
while (scanf("%d%d%d", &N, &M, &K) != EOF){
if (N == 0 && M == 0 && K == 0) break;
Read();
S = 0; // 源点
T = M + N + 1; // 汇点
ans = 0;
for (k = 1; k <= K; k++){
CreatGraph(k);
t = MinCostMaxFlow();
if (!t) break;
ans += t;
}
if (k <= K) puts("-1");
else printf("%d\n", ans);
}
return 0;
}