Time Limit: 4000MS | Memory Limit: 65536K | |
Total Submissions: 15041 | Accepted: 5169 |
Description
Input
Output
Sample Input
1 3 3 1 1 1 0 1 1 1 2 2 1 0 1 1 2 3 1 1 1 2 1 1 1 1 1 3 2 20 0 0 0
Sample Output
4 -1题意:
有N个店家、M个仓库以及K种物品。接下来N行每行K个数,表示每个店家对每一种物品的需求。后面跟着M行,表示每个仓库所存储的每种物品的数目。
最后给出K个N*M的矩阵。对于第k个矩阵,它的第i行第j列表示——第j个仓库运送第k种物品到第i个店家的费用。现在问你能否满足所有店家的需求,若可以输出最小的花费,反之输出-1。
解析:
把K种物品分开单独求解最小费用最大流。如果有一种物品不满足店家的要求的话,说明这种情况不可以。如果都满足话,把每种物品需要的最小费用加起来,就是总的最小花费。这样就转化成常规的最小费用问题了,建图也是常规的建图。
对每种物品,我们都用一下建图方式:
(1)源点到每个仓库建边,容量为拥有该种商品的数目,费用为0。
(2)仓库到店铺建图,容量为店铺对该种物品的需求,费用题目已给出。
(3)店铺到汇点建图,容量为对该种物品的需求,费用为0。
求出每一种物品的最小花费后,我们都要判断一下仓库中拥有该物品的数量能否满足店铺的需求。不满足的话,说明这种情况不可以。如果都满足话,把每种物品需要的最小费用加起来,就是总的最小花费。
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #define maxn 500 #define maxm 11000 #define INF 0x3f3f3f3f using namespace std; int n, m, k; int inset, outset; int sum; struct node { int u, v, cap, flow, cost, next; }; node edge[maxm]; int head[maxn], cnt; int dist[maxn], vis[maxn]; int per[maxn]; int need[100][100]; int have[100][100]; int map[100][100]; int sumneed[100]; void init(){ cnt = 0; memset(head, -1, sizeof(head)); } void add(int u, int v, int w, int c){ node E1 = {u, v, w, 0, c, head[u]}; edge[cnt] = E1; head[u] = cnt++; node E2 = {v, u, 0, 0, -c, head[v]}; edge[cnt] = E2; head[v] = cnt++; } void input(){ memset(sumneed, 0, sizeof(sumneed)); for(int i = 1; i <= n; ++i) for(int j = 1; j <= k; ++j){ scanf("%d", &need[i][j]); sumneed[j] += need[i][j]; } for(int i = 1; i <= m; ++i) for(int j = 1; j <= k; ++j){ scanf("%d", &have[i][j]); } } bool SPFA(int st, int ed){ queue<int>q; for(int i = 0; i <= inset; ++i){ dist[i] = INF; vis[i] = 0; per[i] = -1; } dist[st] = 0; vis[st] = 1; q.push(st); while(!q.empty()){ int u = q.front(); q.pop(); vis[u] = 0; for(int i = head[u]; i != -1; i = edge[i].next){ node E = edge[i]; if(dist[E.v] > dist[u] + E.cost && E.cap > E.flow){ dist[E.v] = dist[u] + E.cost; per[E.v] = i; if(!vis[E.v]){ vis[E.v] = 1; q.push(E.v); } } } } return per[ed] != -1; } void MCMF(int st, int ed, int &cost, int &flow){ flow = 0; cost = 0; while(SPFA(st, ed)){ int mins = INF; for(int i = per[ed]; i != -1; i = per[edge[i ^ 1].v]){ mins = min(mins, edge[i].cap - edge[i].flow); } for(int i = per[ed]; i != -1; i = per[edge[i ^ 1].v]){ edge[i].flow += mins; edge[i ^ 1].flow -= mins; cost += edge[i].cost * mins; } flow += mins; } } void solve(){ outset = 0; inset = n + m + 1; sum = 0; int flag = 1; for(int ii = 1; ii <= k; ++ii){ init(); for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) scanf("%d", &map[i][j]); for(int i = 1; i <= m; ++i) add(outset, i, have[i][ii], 0);//源点向仓库建边 for(int i = 1; i <= n; ++i) add(i + m, inset, need[i][ii], 0);//店铺向汇定建边 for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) add(j, i + m, INF, map[i][j]);//仓库向店铺建边 int cost, flow; MCMF(outset, inset, cost, flow); if(flow == sumneed[ii])//注意 sum += cost; else flag = 0; } if(flag) printf("%d\n", sum); else printf("-1\n"); } int main (){ while(scanf("%d%d%d", &n, &m, &k), n || m || k){ input(); solve(); } return 0; }