一.原题链接: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;
}