题目类型 最小费用最大流
题目意思
给出最多50个用户的最多50种物品的需求数量 和 最多50个供应商的相应物品的供给数量
已知对于某种物品某个用户从某个供应商处拿数量1的货的费用 问要满足所有用户所有种类物品的需求的最少费用, 不能满足输出 -1
解题方法
因为每种物品间不会造成影响 所以每种物品分开处理
建图: 新建一个源点 s 从 s 向每个用户连一条边, 边的容量为这个用户对于当前处理的物品的需求数量, 费用为0
新建一个汇点 t, 对于每个供应商向 t 连一条边, 边的容量为这个供应商对于当前处理的物品的供给数量, 费用为0
即除了源点 s 和汇点 t 外还有 n 个点表示用户 还有 m 个点表示供应商 那么这 n 个点与 这 m 个点之间连边, 边的容量为无限大, 费用为
相应用户向相应供应商取1单位货的费用
那么每次用 spfa 找出一条从 s 到 t 费用最少的增广路, 并记录能增加的最大的流量, 那么最大流就增加那个流量 费用增加这条路径的费用 * 流量
最终如果最大流等于所有用户需求的物品总数表示有合法的方案 总费用加上当前解决的物品的费用
参考代码 - 有疑问的地方在下方留言 看到会尽快回复的
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 50 + 10;
const int INF = 1<<29;
struct Edge {
int from, to, cap, flow, cost;
Edge(int _from, int _to, int _cap, int _flow, int _cost) : from(_from), to(_to), cap(_cap), flow(_flow), cost(_cost) {}
Edge() {}
};
int sum;
struct MCMF {
int n, m, s, t;
vector<Edge>edges;
vector<int>G[maxn*maxn];
int inq[maxn*2], d[maxn*2], p[maxn*2], a[maxn*2];
void init(int n) {
this->n = n;
for( int i=0; i<n; i++ ) G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int cap, int cost) {
edges.push_back(Edge(from, to, cap, 0, cost));
edges.push_back(Edge(to, from, 0, 0, -cost));
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool BellmanFord(int s, int t, int & flow, int & cost) {
for( int i=0; i<n; i++ ) d[i] = INF;
memset(inq, 0, sizeof(inq));
d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;
queue<int>Q;
Q.push(s);
while(!Q.empty()) {
int u = Q.front(); Q.pop();
inq[u] = 0;
for( int i=0; i<G[u].size(); i++ ) {
Edge & e = edges[G[u][i]];
if(e.cap > e.flow && d[e.to] > d[u] + e.cost) {
d[e.to] = d[u] + e.cost;
p[e.to] = G[u][i];
a[e.to] = min(a[u], e.cap - e.flow);
if(!inq[e.to]) { Q.push(e.to); inq[e.to] = 1; }
}
}
}
if(d[t] == INF) return false;
flow += a[t];
cost += d[t] * a[t];
int u = t;
while(u != s) {
edges[p[u]].flow += a[t];
edges[p[u]^1].flow -= a[t];
u = edges[p[u]].from;
}
return true;
}
int Mincost(int s, int t) {
int flow = 0, cost = 0;
while(BellmanFord(s, t, flow, cost));
if(flow < sum) return -1;
else return cost;
}
}MC;
int need[maxn][maxn], have[maxn][maxn];
int main() {
freopen("in", "r", stdin);
int n, m, k;
while(scanf("%d%d%d", &n, &m, &k), n || m || k) {
for( int i=0; i<n; i++ ) for( int j=0; j<k; j++ ) {
scanf("%d", &need[i][j]);
}
for( int i=0; i<m; i++ ) for( int j=0; j<k; j++ ) {
scanf("%d", &have[i][j]);
}
int ans = 0;
for( int h=0; h<k; h++ ) {
MC.init(1+n+m+1);
sum = 0;
for( int i=0; i<n; i++ ) MC.AddEdge(0, 1+i, need[i][h], 0), sum += need[i][h];
for( int i=0; i<m; i++ ) MC.AddEdge(1+n+i, 1+n+m, have[i][h], 0);
for( int i=0; i<n; i++ ) for( int j=0; j<m; j++ ) {
int tmp;
scanf("%d", &tmp);
MC.AddEdge(1+i, 1+n+j, INF, tmp);
}
if(ans == -1) continue;
int tmp = MC.Mincost(0, 1+n+m);
if(tmp == -1) ans = -1;
else ans += tmp;
}
if(ans == -1) printf("-1\n");
else printf("%d\n", ans);
}
return 0;
}