POJ2516 Minimum Cost【最小费用最大流】

题目链接:http://poj.org/problem?id=2516

Minimum Cost
Time Limit: 4000MS   Memory Limit: 65536K
Total Submissions:19928   Accepted: 7064

Description

Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his sale area there are N shopkeepers (marked from 1 to N) which stocks goods from him.Dearboy has M supply places (marked from 1 to M), each provides K different kinds of goods (marked from 1 to K). Once shopkeepers order goods, Dearboy should arrange which supply place provide how much amount of goods to shopkeepers to cut down the total cost of transport. 

It's known that the cost to transport one unit goods for different kinds from different supply places to different shopkeepers may be different. Given each supply places' storage of K kinds of goods, N shopkeepers' order of K kinds of goods and the cost to transport goods for different kinds from different supply places to different shopkeepers, you should tell how to arrange the goods supply to minimize the total cost of transport.

Input

The input consists of multiple test cases. The first line of each test case contains three integers N, M, K (0 < N, M, K < 50), which are described above. The next N lines give the shopkeepers' orders, with each line containing K integers (there integers are belong to [0, 3]), which represents the amount of goods each shopkeeper needs. The next M lines give the supply places' storage, with each line containing K integers (there integers are also belong to [0, 3]), which represents the amount of goods stored in that supply place. 

Then come K integer matrices (each with the size N * M), the integer (this integer is belong to (0, 100)) at the i-th row, j-th column in the k-th matrix represents the cost to transport one unit of k-th goods from the j-th supply place to the i-th shopkeeper. 

The input is terminated with three "0"s. This test case should not be processed.
题目大意:n个商人,m个仓库,每个仓库里有k种货物。给出商人对每个货物的需求,给出仓库里每种货物的储存量,给出每个仓库到每个商人每种货物的单位花费。求在满足商人需求的情况下的最小花费。
思路:
1.这道题输入实在是搞得难受,虽然最后还是写了出来。我都不想解释了 解释在代码里面。
2.关键在于 每个货物是独立的,没有关联,所以可以分别对每个物品进行MCMF()。最后将结果叠加。
3.构图很容易想,对于当前货物,源点到每个仓库连边,容量为仓库里该货物的储存量,花费为0。仓库到每个商人连边,容量为inf,花费为该种货物对该商人的单位花费。每个商人向汇点连边,容量为商人需求量,费用为0.
代码如下:
  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<queue>
  4 #include<algorithm>
  5 #define mem(a, b) memset(a, b, sizeof(a))
  6 const int MAXN = 300;
  7 const int inf = 0x3f3f3f3f;
  8 using namespace std;
  9 
 10 int n, m, k; //n个商人 m个仓库 每个仓库分别有k种货物 
 11 int num[MAXN][MAXN]; //表示第i个人需要第j种货物的数目 
 12 int c_num[MAXN][MAXN]; //表示第i个仓库存储第j种货物的数目 
 13 int vis[2 * MAXN], dis[2 * MAXN], flow[2 * MAXN];
 14 int pre[2 * MAXN], last[2 * MAXN], mincost, maxflow;
 15 queue<int> Q;
 16 
 17 struct Edge
 18 {
 19     int to, next, flow, dis;
 20 }edge[2 * MAXN + MAXN * MAXN];
 21 int head[MAXN], cnt;
 22 
 23 void add(int a, int b, int c, int d)
 24 {
 25     cnt ++;
 26     edge[cnt].to = b;
 27     edge[cnt].flow = c;
 28     edge[cnt].dis = d;
 29     edge[cnt].next = head[a];
 30     head[a] = cnt;
 31 }
 32 
 33 bool spfa(int st, int ed)
 34 {
 35     mem(dis, inf), mem(flow, inf), mem(vis, 0);
 36     Q.push(st);
 37     vis[st] = 1;
 38     dis[st] = 0;
 39     pre[ed] = -1;
 40     while(!Q.empty())
 41     {
 42         int now = Q.front();
 43         Q.pop();
 44         vis[now] = 0;
 45         for(int i = head[now]; i != -1; i = edge[i].next)
 46         {
 47             int to = edge[i].to;
 48             if(edge[i].flow > 0 && dis[to] > dis[now] + edge[i].dis)
 49             {
 50                 dis[to] = dis[now] + edge[i].dis;
 51                 pre[to] = now;
 52                 last[to] = i;
 53                 flow[to] = min(flow[now], edge[i].flow);
 54                 if(!vis[to])
 55                 {
 56                     vis[to] = 1;
 57                     Q.push(to);
 58                 }
 59             }
 60         }
 61     }
 62     return pre[ed] != -1;
 63 }
 64 
 65 void MCMF()
 66 {
 67     int st = 0, ed = m + n + 1;
 68     maxflow = 0, mincost = 0;
 69     while(spfa(st, ed))
 70     {
 71         int now = ed;
 72         maxflow += flow[ed];
 73         mincost += flow[ed] * dis[ed];
 74         while(now != st)
 75         {
 76             edge[last[now]].flow -= flow[ed];
 77             edge[last[now] ^ 1].flow += flow[ed];
 78             now = pre[now];
 79         }
 80     }
 81 }
 82 
 83 int main()
 84 {
 85     while(scanf("%d%d%d", &n, &m, &k) != EOF)
 86     {
 87         int flag = 1;//仓库的储存的物品数目是足够的 
 88         if(n == 0 && m == 0 && k == 0)
 89             break;
 90         for(int i = 1; i <= n; i ++) 
 91             for(int j = 1; j <= k; j ++)
 92                 scanf("%d", &num[i][j]);
 93         for(int i = 1; i <= m; i ++)
 94             for(int j = 1; j <= k; j ++)
 95                 scanf("%d", &c_num[i][j]);
 96         for(int i = 1; i <= k; i ++) //特判 枚举每种货物
 97         {
 98             int x = 0, y = 0;
 99             for(int j = 1; j <= n; j ++)//枚举人 
100                 x += num[j][i];
101             for(int j = 1; j <= m; j ++)//枚举仓库
102                 y += c_num[j][i];
103             if(x > y)
104                 flag = 0;
105         }
106         int ans = 0;
107         for(int K = 1; K <= k; K ++) //k个矩阵 枚举每个物品的费用情况 
108         {
109             cnt = -1, mem(head, -1);
110             for(int i = 1; i <= m; i ++)//源点到仓库建边 
111             {
112                 add(0, i, c_num[i][K], 0);//超级源点 0 
113                 add(i, 0, 0, 0);
114             }
115             for(int i = 1; i <= n; i ++) //仓库向人建边 表示在该物品时 该仓库对该人的单位费用 
116             {
117                 for(int j = 1; j <= m; j ++)
118                 {
119                     int x;
120                     scanf("%d", &x);
121                     if(flag == 0)
122                         continue;
123                     add(j, m + i, inf, x);
124                     add(m + i, j, 0, -x);
125                 }
126             }
127             for(int i = 1; i <= n; i ++)//人到超级汇点 m + n + 1建边 
128             {
129                 add(m + i, m + n + 1, num[i][K], 0);
130                 add(m + n + 1, m + i, 0, 0);
131             }
132             MCMF();
133             ans += mincost;
134         }
135         if(flag)
136             printf("%d\n", ans);
137         else
138             printf("-1\n");
139     }
140     return 0;
141 }
POJ2516

猜你喜欢

转载自www.cnblogs.com/yuanweidao/p/11479735.html