LuoguP1251 餐巾计划问题(费用流)

题目描述

一个餐厅在相继的 NN 天里,每天需用的餐巾数不尽相同。假设第 ii 天需要 r_iri块餐巾( i=1,2,...,N)。餐厅可以购买新的餐巾,每块餐巾的费用为 pp 分;或者把旧餐巾送到快洗部,洗一块需 m 天,其费用为 f 分;或者送到慢洗部,洗一块需 nn天(n>mn>m),其费用为 ss 分(s<fs<f)。

每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。

试设计一个算法为餐厅合理地安排好 NN 天中餐巾使用计划,使总的花费最小。编程找出一个最佳餐巾使用计划。

输入输出格式

输入格式:

由标准输入提供输入数据。文件第 1 行有 1 个正整数 NN,代表要安排餐巾使用计划的天数。

接下来的 NN 行是餐厅在相继的 NN 天里,每天需用的餐巾数。

最后一行包含5个正整数p,m,f,n,sp,m,f,n,s。pp 是每块新餐巾的费用; mm 是快洗部洗一块餐巾需用天数; ff 是快洗部洗一块餐巾需要的费用; nn 是慢洗部洗一块餐巾需用天数; ss 是慢洗部洗一块餐巾需要的费用。

输出格式

将餐厅在相继的 N 天里使用餐巾的最小总花费输出

解题思路:

考虑一下流量问题,发现最大流已经确定了。

此时需要构造一个流使每天的流量都满足要求,

那么就应该在汇点附近约束。

所以需要让每天的餐巾指向汇点。

需要满足直接购买,所以连入新流通入餐巾流中。

考虑餐巾的来源还有洗,那么在前几天的废餐巾指向这个新餐巾。

而废餐巾每天的数量都是固定的,所以连源上就好了。

考虑到可能有余负,向下一天的餐巾连边

建图都讲了边权就不说了。

最后跑一遍费用流就好了。

代码:

 

  1 #include<queue>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 typedef long long lnt;
  6 const lnt oo=0x3f3f3f3f3f3f3f3fll;
  7 struct pnt{
  8     int hd;
  9     int pre;
 10     int lst;
 11     lnt val;
 12     lnt dis;
 13     bool vis;
 14 }p[1000000];
 15 struct ent{
 16     int twd;
 17     int lst;
 18     lnt vls;
 19     lnt dis;
 20 }e[1000000];
 21 int cnt;
 22 int n,m;
 23 int s,t;
 24 int P,M,F,N,S;
 25 std::queue<int>Q;
 26 void ade(int f,int t,lnt v,lnt d)
 27 {
 28     cnt++;
 29     e[cnt].twd=t;
 30     e[cnt].vls=v;
 31     e[cnt].dis=d;
 32     e[cnt].lst=p[f].hd;
 33     p[f].hd=cnt;
 34     return ;
 35 }
 36 bool Spfa(void)
 37 {
 38     while(!Q.empty())Q.pop();
 39     for(int i=1;i<=t;i++)
 40     {
 41         p[i].dis=p[i].val=oo;
 42         p[i].vis=false;
 43     }
 44     p[s].dis=0;
 45     p[s].vis=true;
 46     p[t].pre=-1;
 47     Q.push(s);
 48     while(!Q.empty())
 49     {
 50         int x=Q.front();
 51         Q.pop();
 52         p[x].vis=false;
 53         for(int i=p[x].hd;i;i=e[i].lst)
 54         {
 55             int to=e[i].twd;
 56             if(p[to].dis>p[x].dis+e[i].dis&&e[i].vls>0)
 57             {
 58                 p[to].dis=p[x].dis+e[i].dis;
 59                 p[to].pre=x;
 60                 p[to].val=std::min(p[x].val,e[i].vls);
 61                 p[to].lst=i;
 62                 if(p[to].vis)continue;
 63                 p[to].vis=true;
 64                 Q.push(to);
 65             }
 66         }
 67     }
 68     return p[t].pre!=-1;
 69 }
 70 lnt Ek(void)
 71 {
 72     lnt ans=0;
 73     while(Spfa())
 74     {
 75         ans+=p[t].dis*p[t].val;
 76         for(int i=t;i!=s;i=p[i].pre)
 77         {
 78             e[p[i].lst].vls-=p[t].val;
 79             e[((p[i].lst-1)^1)+1].vls+=p[t].val;
 80         }
 81     }
 82     return ans;
 83 }
 84 int main()
 85 {
 86 //    freopen("a.in","r",stdin);
 87     scanf("%d",&n);
 88     s=n*2+1;
 89     t=s+1;
 90     for(int i=1;i<=n;i++)
 91     {
 92         int v;
 93         scanf("%d",&v);
 94         ade(i,t,v,0);
 95         ade(t,i,0,0);
 96         ade(s,i+n,v,0);
 97         ade(i+n,s,0,0);
 98     }
 99     scanf("%d%d%d%d%d",&P,&M,&F,&N,&S);
100     for(int i=1;i<=n;i++)
101     {
102         ade(s,i,oo,P);
103         ade(i,s,0,-P);
104         if(i+M<=n)
105         {
106             ade(i+n,i+M,oo,F);
107             ade(i+M,i+n,0,-F);
108         }
109         if(i+N<=n)
110         {
111             ade(i+n,i+N,oo,S);
112             ade(i+N,i+n,0,-S);
113         }
114         if(i+1<=n)
115         {
116             ade(i,i+1,oo,0);
117             ade(i+1,i,0,0);
118         }
119     }
120     printf("%lld\n",Ek());
121     return 0;
122 }

 

posted @ 2019-01-02 19:52  Unstoppable728  阅读(166)  评论(0编辑  收藏  举报