码迷,mamicode.com
首页 > 其他好文 > 详细

最小费用最大流

时间:2017-11-12 11:11:44      阅读:138      评论:0      收藏:0      [点我收藏+]

标签:ext   cost   front   names   oid   ati   isp   empty   print   

1、Educational Codeforces Round 29 F.Almost Permutation

(见CF题记《Educational Codeforces Round 29》)

2、uva 11613 Acme Corporation

  题意:有M月,X元素每个月单位保存费用为I,在每个月中,单位生产成本为ni,最大生产数目为mi,单位销售价格为pi,最大销售限制为si,当月生产的X元素最多保存Ei个月份(比如i=1,Ei=3,则可保存月份为1,2,3,4,当月卖出当然不用存储,保存费用为0)。求最大利润?

  思路:采用最小费用最小流,因为本题求最大利润,所有的消耗取正,所有的利润取负,如果当前利润为正,表示已经亏本,停止增广。建立源点,向每个月份建边,容量为mi,边权为ni;每个月向汇点建边,容量为si,边权为-pi;每个月份i向所能保存到的月份j建边,容量为INF,边权为I*(j-i).

技术分享
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<queue>
  5 using namespace std;
  6 
  7 const int maxn = 510;
  8 const int maxe = (maxn + maxn + maxn*maxn) * 2 + 10;
  9 const int INF = 0x3f3f3f3f;
 10 struct edge
 11 {
 12     int from, to, cap, flow, cost, next;
 13     edge(int ff=0,int tt=0,int cc=0,int ww=0,int ss=0,int nn=0):from(ff),to(tt),cap(cc),flow(ww),cost(ss),next(nn){ }
 14 }Edge[maxe];
 15 int Head[maxn], totedge;
 16 
 17 struct MCMF
 18 {
 19     int pre[maxn];//记录在增广路径上,到达i的边的编号
 20     int dist[maxn];
 21     bool vis[maxn];
 22     int N,st,ed;
 23 
 24     void Init()
 25     {
 26         memset(Head, -1, sizeof(Head));
 27         totedge = 0;
 28     }
 29 
 30     void Set(int nodes, int source, int dest)
 31     {
 32         N = nodes, st = source, ed = dest;
 33     }
 34 
 35     void addedge(int from, int to, int cap, int cost)
 36     {
 37         Edge[totedge] = edge(from, to, cap, 0, cost, Head[from]);
 38         Head[from] = totedge++;
 39         Edge[totedge] = edge(to, from, 0, 0, -cost, Head[to]);
 40         Head[to] = totedge++;
 41     }
 42 
 43     bool SPFA(int s, int t)//跑一遍SPFA 找s——t的最少花销路径 且该路径上每一条边不能满流 ,若存在 说明可以继续增广,反之不能  
 44     {
 45         queue<int>q;
 46         memset(dist, INF , sizeof(dist));
 47         memset(vis, 0, sizeof(vis));
 48         memset(pre, -1, sizeof(pre));
 49         
 50         dist[s] = 0;
 51         vis[s] = true;
 52         q.push(s);
 53         while (!q.empty())
 54         {
 55             int u = q.front();
 56             q.pop();
 57             vis[u] = false;
 58 
 59             for (int i = Head[u]; i != -1; i = Edge[i].next)
 60             {
 61                 if (dist[Edge[i].to] > dist[u] + Edge[i].cost&&Edge[i].cap > Edge[i].flow)
 62                 {
 63                     dist[Edge[i].to] = dist[u] + Edge[i].cost;
 64                     pre[Edge[i].to] = i;
 65                     if (!vis[Edge[i].to])
 66                     {
 67                         vis[Edge[i].to] = true;
 68                         q.push(Edge[i].to);
 69                     }
 70                 }
 71             }
 72         }
 73         return pre[t] != -1&&dist[t]<=0;
 74     }
 75 
 76     void cal_MCMF(long long&cost,long long&flow)
 77     {
 78         flow = 0, cost = 0;
 79         while (SPFA(st, ed))
 80         {
 81             //通过反向弧,在源点到汇点的最少花费路径 找最小增广流
 82             int Min = INF;
 83             for (int i = pre[ed]; i != -1; i = pre[Edge[i ^ 1].to])
 84             {
 85                 Min = min(Min, Edge[i].cap - Edge[i].flow);
 86             }
 87             //增广
 88             for (int i = pre[ed]; i != -1; i = pre[Edge[i ^ 1].to])
 89             {
 90                 Edge[i].flow += Min;
 91                 Edge[i ^ 1].flow -= Min;
 92                 cost +=1ll*Edge[i].cost*Min;
 93             }
 94             flow += Min;
 95         }
 96     }
 97 }mcmf;
 98 
 99 int M, I;//总月份,每保存一个月的花费
100 struct node
101 {
102     int mi, ni, pi, si, Ei;//单位生产费用;最大生产量;单位销售价格;最大销售量限制;可保存月份
103     node(int mm=0,int nn=0,int pp=0,int ss=0,int ee=0):mi(mm),ni(nn),pi(pp),si(ss),Ei(ee){ }
104 }parameters[110];
105 int main()
106 {
107     int t;
108     scanf("%d", &t);
109     int Case = 1;
110     while (t--)
111     {
112         scanf("%d%d", &M, &I);
113         for (int i = 1; i <= M; i++)
114         {
115             scanf("%d%d%d%d%d", &parameters[i].mi, &parameters[i].ni, &parameters[i].pi, &parameters[i].si, &parameters[i].Ei);
116         }
117         mcmf.Init();
118         mcmf.Set(2 * M + 2, 0, 2 * M + 1);
119         for (int i = 1; i <= M; i++)
120         {
121             mcmf.addedge(0, 2 * i - 1, parameters[i].ni, parameters[i].mi);//本题求最大利润,费用+
122             mcmf.addedge(2 * i, 2 * M + 1, parameters[i].si,-parameters[i].pi);//本题求最大利润,卖出-
123         }
124         for (int i = 1; i <= M; i++)
125         {
126             for (int j = i; j <= min(i + parameters[i].Ei, M); j++)
127             {
128                 mcmf.addedge(2 * i - 1, 2 * j, INF, I*(j - i));//I*(j - i)表示每单位从i月保存至j月需要的费用
129             }
130         }
131         long long flow, cost;
132         mcmf.cal_MCMF(cost, flow);
133         printf("Case %d: %lld\n", Case++, -cost);
134     }
135     return 0;
136 }
View Code

 

最小费用最大流

标签:ext   cost   front   names   oid   ati   isp   empty   print   

原文地址:http://www.cnblogs.com/ivan-count/p/7594644.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!