UVA11613 Acme Corporation —— 最小费用流(流量不固定的最小费用流)
题目链接:https://vjudge.net/problem/UVA-11613
题意:
商品X在第i个月内:生产一件需要花费mi元,最多可生产ni件,销售一件(在这个月内销售,而不管它是在那个月生产的)的价格是pi元, 最多能销售si件, 在这个月生产的产品的保质期为Ei。对于所有商品X,每“保质”一个月,就要花费I元。问:在M个月内,最多能获利多少?
题解:
最小费用流问题,建图方式如下(详情在《训练指南》P367):
1.把每个月拆成两个点,一个点为生产,另一个点为销售。
2.如果月x生产的商品能够放到月y内销售,就在月x的生产点和月y的销售点之间连一条边,容量为月x的最大生产量, 花费为0。
3.建立超级源点,并且连向每个月的生产点,边的容量为该月的最大生产量, 边的花费为该月生产一件商品所需的花费。
4.建立超级汇点,并且连向每个月的销售点,边的容量为该月的最大销售量, 边的花费为该月单间商品的售价的负值。
5.跑最小费用流算法:当增广得到的单位费用和小于0时,表明收入大于敷出(因为收入在图中设置为负值),继续增广;当单位费用和大于等于0时,表明收入小于敷出,再继续增广,利润反而降低,所以在此时就应该停止增广。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <cmath> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const int INF = 2e9; 15 const LL LNF = 9e18; 16 const int mod = 1e9+7; 17 const int MAXM = 1e5+10; 18 const int MAXN = 2e2+10; 19 20 struct Edge 21 { 22 int to, next, cap, flow, cost; 23 }edge[MAXM]; 24 int tot, head[MAXN]; 25 int pre[MAXN], dis[MAXN]; 26 bool vis[MAXN]; 27 int N; 28 29 void init(int n) 30 { 31 N = n; 32 tot = 0; 33 memset(head, -1, sizeof(head)); 34 } 35 36 void add(int u, int v, int cap, int cost) 37 { 38 edge[tot].to = v; edge[tot].cap = cap; edge[tot].cost = cost; 39 edge[tot].flow = 0; edge[tot].next = head[u]; head[u] = tot++; 40 edge[tot].to = u; edge[tot].cap = 0; edge[tot].cost = -cost; 41 edge[tot].flow = 0; edge[tot].next = head[v]; head[v] = tot++; 42 } 43 44 bool spfa(int s, int t) 45 { 46 queue<int>q; 47 for(int i = 0; i<N; i++) 48 { 49 dis[i] = INF; 50 vis[i] = false; 51 pre[i] = -1; 52 } 53 54 dis[s] = 0; 55 vis[s] = true; 56 q.push(s); 57 while(!q.empty()) 58 { 59 int u = q.front(); 60 q.pop(); 61 vis[u] = false; 62 for(int i = head[u]; i!=-1; i = edge[i].next) 63 { 64 int v = edge[i].to; 65 if(edge[i].cap>edge[i].flow && dis[v]>dis[u]+edge[i].cost) 66 { 67 dis[v] = dis[u]+edge[i].cost; 68 pre[v] = i; 69 if(!vis[v]) 70 { 71 vis[v] = true; 72 q.push(v); 73 } 74 } 75 } 76 } 77 if(pre[t]==-1) return false; 78 if(dis[t]>=0) return false; //当单位费用和大于等于0时,即停止增广 79 return true; 80 } 81 82 int minCostMaxFlow(int s, int t, LL &cost) 83 { 84 int flow = 0; 85 cost = 0; 86 while(spfa(s,t)) 87 { 88 int Min = INF; 89 for(int i = pre[t]; i!=-1; i = pre[edge[i^1].to]) 90 { 91 if(Min>edge[i].cap-edge[i].flow) 92 Min = edge[i].cap-edge[i].flow; 93 } 94 for(int i = pre[t]; i!=-1; i = pre[edge[i^1].to]) 95 { 96 edge[i].flow += Min; 97 edge[i^1].flow -= Min; 98 cost += 1LL*edge[i].cost*Min; 99 } 100 flow += Min; 101 } 102 return flow; 103 } 104 105 int main() 106 { 107 int T, M, I; 108 scanf("%d", &T); 109 for(int kase = 1; kase<=T; kase++) 110 { 111 scanf("%d%d", &M, &I); 112 int start = 0, end = 2*M+1; 113 init(2*M+2); 114 115 for(int i = 1; i<=M; i++) 116 { 117 int m, n, p, s, E; 118 scanf("%d%d%d%d%d", &m,&n,&p,&s,&E); 119 add(start, i, n, m); 120 for(int j = i; j<=min(M, i+E); j++) 121 add(i, M+j, n, (j-i)*I); 122 add(M+i, end, s, -p); 123 } 124 125 LL min_cost; 126 minCostMaxFlow(start, end, min_cost); 127 printf("Case %d: %lld\n", kase, -min_cost); 128 } 129 }