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 }
View Code

 

posted on 2017-12-26 21:03  h_z_cong  阅读(457)  评论(0编辑  收藏  举报

导航