题意分析:
N个店主,M个供货商,K种货物,每个店主都有自己需要的货物数量,每个供货商都会提供一定数量的货物,每个供货商给店主提供不同货物的单位价格不同,现在问题来了:供货商如何花费最少的费用给店主提供上货物呢?最少费用是多少?无法满足要求则输出-1。
解题思路:
这题如果将店主的需要货物拆点,供货商的提供货物拆点,再来个超级源汇点,边的个数多的吓人。。。。。
发现可以一种货物计算一次费用,返回的最大流就是这种货物能够提供的最大总数,如果这个最大流<店主需要的量,那么就是-1了。
于是我们一种货物建一次图,源点到供货商连一条边,容量为供货量,费用为0,汇点和店主连一条边,容量为需求量,费用为0,供货商和店主连边,容量为INF,费用为当前矩阵对应的费用。此题得解。
个人感受:
个人思路一直是第一行的解题思路。。。。。各种拆点。。。。。这回知道连图都能拆了。。。。
具体代码如下:
#include<algorithm> #include<cctype> #include<cmath> #include<cstdio> #include<cstring> #include<iomanip> #include<iostream> #include<map> #include<queue> #include<set> #include<sstream> #include<stack> #include<string> #define ll long long #define pr(x) cout << #x << " = " << (x) << '\n'; using namespace std; const int MAXN = 200; const int MAXM = 2e4; const int INF = 0x3f3f3f3f; struct Edge { int to,next,cap,flow,cost; }edge[MAXM]; int head[MAXN], tol, nk[60][60], mk[60][60], need[60], have[60]; int pre[MAXN],dis[MAXN]; bool vis[MAXN]; int N;//节点总个数,节点编号从0~N-1 void init(int n) { N = n; tol = 0; memset(need, 0, sizeof need); memset(have, 0, sizeof have); } void addedge(int u,int v,int cap,int cost) { edge[tol].to = v; edge[tol].cap = cap; edge[tol].cost = cost; edge[tol].flow = 0; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cap = 0; edge[tol].cost = -cost; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++; } bool spfa(int s,int t) { queue<int>q; for(int i = 0;i < N;i++) { dis[i] = INF; vis[i] = false; pre[i] = -1; } dis[s] = 0; vis[s] = true; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for(int i = head[u]; i != -1;i = edge[i].next) { int v = edge[i].to; if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost ) { dis[v] = dis[u] + edge[i].cost; pre[v] = i; if(!vis[v]) { vis[v] = true; q.push(v); } } } } if(pre[t] == -1)return false; else return true; } //返回的是最大流, cost存的是最小费用 int minCostMaxflow(int s,int t,int &cost) { int flow = 0; while(spfa(s,t)) { int Min = INF; for(int i = pre[t];i != -1;i = pre[edge[i^1].to]) { if(Min > edge[i].cap - edge[i].flow) Min = edge[i].cap - edge[i].flow; } for(int i = pre[t];i != -1;i = pre[edge[i^1].to]) { edge[i].flow += Min; edge[i^1].flow -= Min; cost += edge[i].cost * Min; } flow += Min; } return flow; } int main() { int n, m, k; while (~scanf("%d%d%d", &n, &m, &k) && (n|m|k)) { init(n + m + 2); int s = 0, t = n + m + 1; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= k; ++j) scanf("%d", &nk[i][j]), need[j] += nk[i][j]; } for (int i = 1; i <= m; ++i) { for (int j = 1; j <= k; ++j) scanf("%d", &mk[i][j]), have[j] += mk[i][j]; } bool flag = 0; int x = 0, ans = 0; for (int l = 1; l <= k; ++l) { tol = 0; memset(head, -1, sizeof head); for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { scanf("%d", &x); addedge(n + j, i, mk[j][l], x); } } for (int i = 1; i <= n; ++i) addedge(i, t, nk[i][l], 0); for (int i = 1; i <= m; ++i) addedge(s, i + n, mk[i][l], 0); int flow = minCostMaxflow(s, t, ans); if (flow < need[l]) flag = 1; } if (flag) printf("-1\n"); else printf("%d\n", ans); } return 0; }