最近在看最小费用最大流,找了道题,练了练,还是比较简单的。
题意很明确,有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; }