一.原题链接:http://poj.org/problem?id=2516
二.题目大意:Dearboy是销售商,有N个店主帮他卖东西,他有M个生产地,有K种商品,每个生产地的每种商品给每个店主的花费都是不同的,求在满足所有店主的预定下,(不满足输出-1),求最小花费。
三.思路:明显的最小费用最大流问题,真的很明显。刚开始还想把K个商品拆了中间连一条其花费的线,听说会超时,建议不要试。其实可以每种商品求一次最大流,如果其中一种商品不满足店主需求,输出-1,全部满足直接把它们都加起来。
建图如下:(求K次)
1.超级源点S和每个生产地连起来,容量为其产出,花费为0。
2.超级汇点T和每个店主连起来,容量为其需求,花费为0。(每次都需要满流,不然输出-1)
3.生产地和店主之间连对应的花费。
注意事项:
1.它给的是单位容量的花费,所以记得要乘上容量啊,就是说在求花费的时候,在索引路的时候,要顺手把增广的流乘以单位花费啊,就是在这里WA了一次。画图画一边就知道是自己傻逼了。
2.我为什么要使用堆空间呢,因为我想在一个函数里面建图,这样每求一次最大流后它就会自动析构,使用栈空间又怕爆,所以。。
四.代码:
#include <iostream> #include <cstdio> #include <queue> #include <cstring> #include <cstdlib> using namespace std; const int INF = 0x3f3f3f3f, MAX_SIZE = 1000; class AdjList { public: int *head, cnt; struct Edge { int cost, cap, v, next; }*edges; AdjList() { edges = new Edge[MAX_SIZE*MAX_SIZE]; head = new int[MAX_SIZE]; cnt = 0; memset(head, -1, sizeof(int)*MAX_SIZE); } ~AdjList() { delete[] edges; delete[] head; } void addEdge(int u, int v, int cap, int cost) { edges[cnt].v = v, edges[cnt].cap = cap, edges[cnt].cost = cost, edges[cnt].next = head[u]; head[u] = cnt++; edges[cnt].v = u, edges[cnt].cap = 0, edges[cnt].cost = -cost, edges[cnt].next = head[v]; head[v] = cnt++; } }; class MinCost { public: AdjList G; int *dist, *pre, *path, s, t; MinCost() { dist = new int[MAX_SIZE]; pre = new int[MAX_SIZE]; path = new int[MAX_SIZE]; } ~MinCost() { delete[] dist; delete[] pre; delete[] path; } bool SPFA() { bool inQue[MAX_SIZE]; queue <int> que; int cur, v, i; memset(dist, INF, sizeof(int)*MAX_SIZE); memset(inQue, 0, sizeof(inQue)); memset(pre, -1, sizeof(int)*MAX_SIZE); dist[s] = 0; que.push(s); inQue[s] = true; while(!que.empty()){ cur = que.front(); que.pop(); inQue[cur] = false; for(i = G.head[cur]; i != -1; i = G.edges[i].next){ v = G.edges[i].v; if(G.edges[i].cap && dist[v] > dist[cur] + G.edges[i].cost){ dist[v] = dist[cur] + G.edges[i].cost; pre[v] = cur; path[v] = i; if(!inQue[v]){ que.push(v); inQue[v] = true; } } } } return pre[t] != -1; } int ford_fulkerson(int &maxFlow) { int sum = 0, u, v, minFlow, i; maxFlow = 0; while(SPFA()){ minFlow = INF; for(u = pre[t], v = t; u != -1; v = u, u = pre[u]){ i = path[v]; minFlow = min(minFlow, G.edges[i].cap); } maxFlow += minFlow; for(u = pre[t], v = t; u != -1; v = u, u = pre[u]){ i = path[v]; G.edges[i].cap -= minFlow; G.edges[i^1].cap += minFlow; sum += minFlow*G.edges[i].cost; } } return sum; } }; const int MAX_N = 58; int N, M, K, orders[MAX_N][MAX_N], supply[MAX_N][MAX_N], cost[MAX_N][MAX_N][MAX_N]; int getMinCost(int foodId) { MinCost poj2516; int i, j, s, t, maxFlow, sumOrder, res; s = M+N+1, t = M+N+2; poj2516.s = s, poj2516.t = t; sumOrder = 0; for(i = 1; i <= M; i++) poj2516.G.addEdge(s, i, supply[i][foodId], 0); for(i = 1; i <= N; i++){ poj2516.G.addEdge(i + M, t, orders[i][foodId], 0); sumOrder += orders[i][foodId]; } for(i = 1; i <= M; i++) for(j = 1; j <= N; j++) poj2516.G.addEdge(i, j+M, INF, cost[foodId][j][i]); res = poj2516.ford_fulkerson(maxFlow); if(sumOrder != maxFlow) return -1; else return res; } int main() { //freopen("in.txt", "r", stdin); int i, j, t, temp, sum; while(~scanf("%d%d%d", &N, &M, &K) && (N+M+K)){ for(i = 1; i <= N; i++) for(j = 1; j <= K; j++) scanf("%d", &orders[i][j]); for(i = 1; i <= M; i++) for(j = 1; j <= K; j++) scanf("%d", &supply[i][j]); for(t = 1; t <= K; t++) for(i = 1; i <= N; i++) for(j = 1; j <= M; j++) scanf("%d", &cost[t][i][j]); sum = 0; for(t = 1; t <= K; t++){ temp = getMinCost(t); if(temp != -1) sum += temp; else{ sum = -1; break; } } printf("%d\n", sum); } return 0; }