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 }