题目链接:http://poj.org/problem?id=2516
解题思路:
最小费用最大流,这个没什么疑问。但此题小难点在于读题,大难点在于建图。
首先,供应量小于需求量的时候直接输出“-1”。
供大于或等于求的情况,一开始我将每个供应商和每个购买人都拆成K个点,将所有供应商的点和超级源点相连,流量限制为库存量,费用为0;将所有购买人的点和超级汇点相连,流量限制为购买量,费用为0;而购买方和供应方之间的连线的流量限制则为inf,费用如题目中给出的。但是这种建图方式一直T......一度绝望到以为我的模板有问题,修修补补了半天,还是T......上网查了题解,发现大家的建图方式跟我不一样:大家都是把根据K种商品,建K个图逐一求最小费用最大流,答案就是K个图的最小费用之和。稍微改了一下,AC.......醉........至于为什么........我也不太懂,容我明天去问问师兄。
AC代码:
1 #include <cstdio> 2 #include <vector> 3 #include <queue> 4 #include <cstring> 5 using namespace std; 6 7 const int MAXN = 5000; 8 const int MAXM = 100000; 9 const int INF = 0x3f3f3f3f; 10 struct rec { 11 int from, to, cost, cap; 12 }r[55][2550]; 13 struct Edge { 14 int to, next, cap, flow, cost; 15 }edge[MAXM]; 16 int head[MAXN], tol; 17 int pre[MAXN], dis[MAXN]; 18 bool vis[MAXN]; 19 int N; 20 void init(int n) { 21 N = n; 22 tol = 0; 23 memset(head, -1, sizeof(head)); 24 } 25 void addedge(int u, int v, int cap, int cost) { 26 edge[tol].to = v; 27 edge[tol].cap = cap; 28 edge[tol].cost = cost; 29 edge[tol].flow = 0; 30 edge[tol].next = head[u]; 31 head[u] = tol++; 32 edge[tol].to = u; 33 edge[tol].cap = 0; 34 edge[tol].cost = -cost; 35 edge[tol].flow = 0; 36 edge[tol].next = head[v]; 37 head[v] = tol++; 38 } 39 bool spfa(int s, int t) { 40 queue<int>q; 41 for (int i = 0; i < N; i++) { 42 dis[i] = INF; 43 vis[i] = false; 44 pre[i] = -1; 45 } 46 dis[s] = 0; 47 vis[s] = true; 48 q.push(s); 49 while (!q.empty()) { 50 int u = q.front(); 51 q.pop(); 52 vis[u] = false; 53 for (int i = head[u]; i != -1; i = edge[i].next) { 54 int v = edge[i].to; 55 if (edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost){ 56 dis[v] = dis[u] + edge[i].cost; 57 pre[v] = i; 58 if (!vis[v]){ 59 vis[v] = true; 60 q.push(v); 61 } 62 } 63 } 64 } 65 if (pre[t] == -1) return false; 66 else return true; 67 } 68 int minCostMaxflow(int s, int t, int &cost){ 69 int flow = 0; 70 cost = 0; 71 while (spfa(s, t)) { 72 int Min = INF; 73 for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]) { 74 if (Min > edge[i].cap - edge[i].flow) 75 Min = edge[i].cap - edge[i].flow; 76 } 77 for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]) { 78 edge[i].flow += Min; 79 edge[i ^ 1].flow -= Min; 80 cost += edge[i].cost * Min; 81 } 82 flow += Min; 83 } 84 return flow; 85 } 86 int sup[55][55], buy[55][55]; 87 int main() { 88 int N, M, K; 89 int need[53], have[53]; 90 while (scanf("%d%d%d", &N, &M, &K) == 3 && (N || M || K)) { 91 memset(need, 0, sizeof(need)); 92 memset(have, 0, sizeof(have)); 93 int c; 94 for (int i = 1; i <= N; i++) { 95 for (int j = 1; j <= K; j++) { 96 scanf("%d", &c); 97 need[j] += c; 98 buy[j][i] = c; 99 } 100 } 101 for (int i = 1; i <= M; i++) { 102 for (int j = 1; j <= K; j++) { 103 scanf("%d", &c); 104 have[j] += c; 105 sup[j][i] = c; 106 } 107 } 108 bool yes = true; 109 for (int j = 1; j <= K; j++) { 110 if (have[j]<need[j]) yes = false; 111 } 112 113 int ans = 0; 114 for (int k = 1; k <= K; k++) { 115 if (yes) 116 init(N + M + 2); 117 for (int i = 1; i <= N; i++) { 118 for (int j = 1; j <= M; j++) { 119 scanf("%d", &c); 120 if (yes) 121 addedge(j, M + i, INF, c); 122 } 123 } 124 if (yes) { 125 for (int i = 1; i <= M; i++) 126 addedge(0, i, sup[k][i], 0); 127 for (int i = 1; i <= N; i++) 128 addedge(M + i, N + M + 1, buy[k][i], 0); 129 int cost; 130 minCostMaxflow(0, N + M + 1, cost); 131 ans += cost; 132 } 133 } 134 if (!yes) 135 printf("-1 "); 136 else 137 printf("%d ", ans); 138 } 139 return 0; 140 }