题意:
。。。
思路:
这里是求最大流的最小费用流。
k个物品是无关的,可以分开搞,最后把费用加起来。
参考了大神代码
const int Maxn = 50;
const int MaxV = 105;
struct Edge {
int to, cap, cost;
};
vector<Edge> E;
vector<int> G[MaxV+5];
int offer[Maxn+5][Maxn+5], need[Maxn+5][Maxn+5], carriage[Maxn+5][Maxn+5][Maxn+5], n, m, k;
int inq[MaxV+5], preE[MaxV+5], preV[MaxV+5], mc[MaxV+5], dist[MaxV+5];
int spfa (int s, int t) {
queue<int> q;
memset(inq, 0, sizeof(inq));
fill(mc, mc+t+2, inf);
fill(dist, dist+t+2, inf);
dist[s] = 0;
inq[s] = 1;
q.push(s);
while (!q.empty()) {
int fr = q.front();q.pop();
inq[fr] = 0;
int sz = G[fr].size();
rep(i, 0, sz-1) {
Edge &e = E[G[fr][i]];
if (e.cap && dist[fr] + e.cost < dist[e.to]) {
preV[e.to] = fr;
preE[e.to] = G[fr][i];
dist[e.to] = dist[fr] + e.cost;
mc[e.to] = min (e.cap, mc[fr]);
if (!inq[e.to]) {
q.push(e.to);inq[e.to] = 1;
}
}
}
}
//rep(i, 1, t) cout << "d" << i << ": " << dist[i] << endl;
//rep(i, 1, t) cout << "pre" << i << ": " << preV[i] << endl;
if (dist[t] < inf) return dist[t];
return -1;
}
void add_edge(int from, int to, int cap, int cost) {
E.push_back( (Edge){to, cap, cost} );
G[from].push_back(E.size()-1);
E.push_back( (Edge){from, 0, -cost} );
G[to].push_back(E.size()-1);
}
// supply places i: i, shopkeeper i: i+m
void build(int s, int t, int x) {
rep(i, 1, m) add_edge(s, i, offer[i][x], 0);
rep(i, 1, n) add_edge(i+m, t, need[i][x], 0);
rep(i, 1, m) rep(j, 1, n) add_edge(i, j+m, need[j][x], carriage[x][j][i]);
}
void change(int s, int t, int f) {
int now = t;
while (now != s) {
int idx = preE[now];
E[idx].cap -= f;
E[idx^1].cap += f;
now = preV[now];
}
}
int work(int x) {
int s = 0, t = n+m+1;
rep(i, s, t) G[i].clear();
E.clear();
build(s, t, x);
int ret = 0;
while (true) {
int tmp = spfa(s, t);
if (tmp < 0) break;
change(s, t, mc[t]);
ret += tmp*mc[t];
}
return ret;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
#endif
SPEED_UP
while (cin >> n >> m >> k && n+m+k) {
vector<int> sum_of_need(k+1), sum_of_offer(k+1);
rep(i, 1, n) rep(j, 1, k) {cin >> need[i][j];sum_of_need[j] += need[i][j];}
rep(i, 1, m) rep(j, 1, k) {cin >> offer[i][j];sum_of_offer[j] += offer[i][j];}
rep(i, 1, k) rep(j, 1, n) rep(z, 1, m) cin >> carriage[i][j][z];
// 判断 impossible
int ok = 1;
rep(i, 1, k) if (sum_of_offer[i] < sum_of_need[i]) {
ok = 0;break;
}
if (!ok) {cout << -1 << endl;continue;}
int sum = 0;
rep(i, 1, k) {
sum += work(i);
}
cout << sum << endl;
}
return 0;
}