Description
Input
Output
题目大意:N个客户M个仓库K种物品。已知每个客户需要的每种物品的数量,和每个仓库拥有的每种物品的数量,和每个仓库运送每种物品到每个顾客的花费,求满足所有顾客的最小花费。
思路:由于每个物品独立,分开每个物品建图。考虑物品x,建立附加源点S,从S到每个仓库连一条边,容量为该仓库拥有物品x的数量,费用为0;从每个客户连一条边到附加汇点T,容量为每个客户需要的物品x的数量,费用为0;从每个仓库连一条边到每个客户,容量为无穷大,费用为仓库到客户运输物品x的花费。求最小费用最大流,若都满流,K个物品相加就是答案。若有一个流不满,则输出-1(不能满足顾客需求)。
PS:记得读完数据。
PS2:再次提出稠密图应该用ZKW费用流。
PS3:ZKW费用流写挫了WA了一次,这玩意儿好难写……
代码(266MS):
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 8 const int MAXV = 110; 9 const int MAXE = MAXV * MAXV; 10 const int INF = 0x7fffffff; 11 12 struct ZEK_FLOW { 13 int head[MAXV], dis[MAXV]; 14 int next[MAXE], to[MAXE], cap[MAXE], cost[MAXE]; 15 int n, ecnt, st, ed; 16 17 void init() { 18 memset(head, 0, sizeof(head)); 19 ecnt = 2; 20 } 21 22 void add_edge(int u, int v, int c, int w) { 23 to[ecnt] = v; cap[ecnt] = c; cost[ecnt] = w; next[ecnt] = head[u]; head[u] = ecnt++; 24 to[ecnt] = u; cap[ecnt] = 0; cost[ecnt] = -w; next[ecnt] = head[v]; head[v] = ecnt++; 25 } 26 27 void SPFA() { 28 for(int i = 1; i <= n; ++i) dis[i] = INF; 29 priority_queue<pair<int, int> > que; 30 dis[st] = 0; que.push(make_pair(0, st)); 31 while(!que.empty()) { 32 int u = que.top().second, d = -que.top().first; que.pop(); 33 if(d != dis[u]) continue; 34 for(int p = head[u]; p; p = next[p]) { 35 int &v = to[p]; 36 if(cap[p] && dis[v] > d + cost[p]) { 37 dis[v] = d + cost[p]; 38 que.push(make_pair(-dis[v], v)); 39 } 40 } 41 } 42 int t = dis[ed]; 43 for(int i = 1; i <= n; ++i) dis[i] = t - dis[i]; 44 } 45 46 int minCost, maxFlow; 47 bool vis[MAXV]; 48 49 int add_flow(int u, int aug) { 50 if(u == ed) { 51 maxFlow += aug; 52 minCost += dis[st] * aug; 53 return aug; 54 } 55 vis[u] = true; 56 int now = aug; 57 for(int p = head[u]; p; p = next[p]) { 58 int &v = to[p]; 59 if(cap[p] && !vis[v] && dis[u] == dis[v] + cost[p]) { 60 int t = add_flow(v, min(now, cap[p])); 61 cap[p] -= t; 62 cap[p ^ 1] += t; 63 now -= t; 64 if(!now) break; 65 } 66 } 67 return aug - now; 68 } 69 70 bool modify_label() { 71 int d = INF; 72 for(int u = 1; u <= n; ++u) if(vis[u]) { 73 for(int p = head[u]; p; p = next[p]) { 74 int &v = to[p]; 75 if(cap[p] && !vis[v]) d = min(d, dis[v] + cost[p] - dis[u]); 76 } 77 } 78 if(d == INF) return false; 79 for(int i = 1; i <= n; ++i) if(vis[i]) dis[i] += d; 80 return true; 81 } 82 83 int min_cost_flow(int ss, int tt, int nn) { 84 st = ss, ed = tt, n = nn; 85 minCost = maxFlow = 0; 86 SPFA(); 87 while(true) { 88 while(true) { 89 for(int i = 1; i <= n; ++i) vis[i] = 0; 90 if(!add_flow(st, INF)) break; 91 } 92 if(!modify_label()) break; 93 } 94 return minCost; 95 } 96 } G; 97 98 int n, m, k; 99 int need[MAXV][MAXV], have[MAXV][MAXV], sum[MAXV]; 100 int mat[MAXV][MAXV]; 101 102 int main() { 103 while(scanf("%d%d%d", &n, &m, &k) != EOF) { 104 if(n == 0 && m == 0 && k == 0) break; 105 memset(sum, 0, sizeof(sum)); 106 for(int i = 1; i <= n; ++i) 107 for(int j = 1; j <= k; ++j) scanf("%d", &need[i][j]), sum[j] += need[i][j]; 108 for(int i = 1; i <= m; ++i) 109 for(int j = 1; j <= k; ++j) scanf("%d", &have[i][j]); 110 int ans = 0; bool flag = true; 111 for(int x = 1; x <= k; ++x) { 112 for(int i = 1; i <= n; ++i) 113 for(int j = 1; j <= m; ++j) scanf("%d", &mat[i][j]); 114 if(!flag) continue; 115 G.init(); 116 int ss = n + m + 1, tt = ss + 1; 117 for(int i = 1; i <= m; ++i) G.add_edge(ss, i, have[i][x], 0); 118 for(int i = 1; i <= n; ++i) G.add_edge(i + m, tt, need[i][x], 0); 119 for(int i = 1; i <= n; ++i) 120 for(int j = 1; j <= m; ++j) G.add_edge(j, i + m, INF, mat[i][j]); 121 ans += G.min_cost_flow(ss, tt, tt); 122 flag = (G.maxFlow == sum[x]); 123 } 124 if(flag) printf("%d\n", ans); 125 else puts("-1"); 126 } 127 }