餐巾计划问题(费用流)
Posted fighting-sh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了餐巾计划问题(费用流)相关的知识,希望对你有一定的参考价值。
餐巾计划问题
https://www.luogu.org/problemnew/show/P1251
题目描述
一个餐厅在相继的 N 天里,每天需用的餐巾数不尽相同。假设第 i 天需要 ri?块餐巾( i=1,2,...,N)。餐厅可以购买新的餐巾,每块餐巾的费用为 p 分;或者把旧餐巾送到快洗部,
洗一块需 m 天,其费用为 f 分;或者送到慢洗部,洗一块需 n 天(n>m),其费用为 s 分(s<f)。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
试设计一个算法为餐厅合理地安排好 N 天中餐巾使用计划,使总的花费最小。编程找出一个最佳餐巾使用计划。
输入输出格式
输入格式:
由标准输入提供输入数据。文件第 1 行有 1 个正整数 N,代表要安排餐巾使用计划的天数。
接下来的 N 行是餐厅在相继的 N 天里,每天需用的餐巾数。
最后一行包含5个正整数p,m,f,n,s。p 是每块新餐巾的费用; m 是快洗部洗一块餐巾需用天数; f 是快洗部洗一块餐巾需要的费用; n 是慢洗部洗一块餐巾需用天数; s 是慢洗部洗一块餐巾需要的费用。
输出格式:
将餐厅在相继的 N 天里使用餐巾的最小总花费输出
输入输出样例
说明
N<=2000
ri<=10000000
p,f,s<=10000
时限4s
参考博客:https://www.luogu.org/blog/user31955/solution-p1251
注意开long long
1 #include<iostream> 2 #include<algorithm> 3 #include<queue> 4 #include<cstring> 5 using namespace std; 6 7 const int INF=0x3f3f3f3f; 8 const int N=500005; 9 const int M=500005; 10 int top; 11 long long dist[N]; 12 int pre[N]; 13 bool vis[N]; 14 int c[N]; 15 int maxflow; 16 17 struct Vertex{ 18 int first; 19 }V[N]; 20 struct Edge{ 21 int v,next; 22 int cap,flow,cost; 23 }E[M]; 24 25 void init(){ 26 memset(V,-1,sizeof(V)); 27 top=0; 28 maxflow=0; 29 } 30 31 void add_edge(int u,int v,int c,int cost){ 32 E[top].v=v; 33 E[top].cap=c; 34 E[top].flow=0; 35 E[top].cost=cost; 36 E[top].next=V[u].first; 37 V[u].first=top++; 38 } 39 40 void add(int u,int v,int c,int cost){ 41 add_edge(u,v,c,cost); 42 add_edge(v,u,0,-cost); 43 } 44 45 bool SPFA(int s,int t,int n){ 46 int i,u,v; 47 queue<int>qu; 48 memset(vis,false,sizeof(vis)); 49 memset(c,0,sizeof(c)); 50 memset(pre,-1,sizeof(pre)); 51 for(i=1;i<=n;i++){ 52 dist[i]=0x3f3f3f3f3f3f3f3f; 53 } 54 vis[s]=true; 55 c[s]++; 56 dist[s]=0; 57 qu.push(s); 58 while(!qu.empty()){ 59 u=qu.front(); 60 qu.pop(); 61 vis[u]=false; 62 for(i=V[u].first;~i;i=E[i].next){ 63 v=E[i].v; 64 if(E[i].cap>E[i].flow&&dist[v]>dist[u]+E[i].cost){ 65 dist[v]=dist[u]+E[i].cost; 66 pre[v]=i; 67 if(!vis[v]){ 68 c[v]++; 69 qu.push(v); 70 vis[v]=true; 71 if(c[v]>n){ 72 return false; 73 } 74 } 75 } 76 } 77 } 78 if(dist[t]==0x3f3f3f3f3f3f3f3f){ 79 return false; 80 } 81 return true; 82 } 83 84 long long MCMF(int s,int t,int n){ 85 int d; 86 int i; 87 long long mincost; 88 mincost=0; 89 while(SPFA(s,t,n)){ 90 d=INF; 91 for(i=pre[t];~i;i=pre[E[i^1].v]){ 92 d=min(d,E[i].cap-E[i].flow); 93 } 94 maxflow+=d; 95 for(i=pre[t];~i;i=pre[E[i^1].v]){ 96 E[i].flow+=d; 97 E[i^1].flow-=d; 98 } 99 mincost+=dist[t]*d; 100 // cout<<d<<endl; 101 } 102 return mincost; 103 } 104 105 106 107 int main(){ 108 int n,m; 109 int v,u,w,c; 110 int s,t; 111 cin>>n; 112 init(); 113 s=0,t=n+n+1; 114 for(int i=1;i<=n;i++){ 115 cin>>w; 116 add(s,i,w,0);//每天晚上从起点获得x条脏餐巾 117 add(n+i,t,w,0);//每天白天,向汇点提供x条干净的餐巾,流满时表示第i天的餐巾够用 118 } 119 int P,t1,t2,cost1,cost2; 120 cin>>P>>t1>>cost1>>t2>>cost2; 121 for(int i=1;i<=n;i++){ 122 add(s,i+n,INF,P);//每天早上可以购买餐巾 123 if(i+1<=n) add(i,i+1,INF,0);//每天晚上可以将脏餐巾留到第二天晚上 124 if(i+t1<=n) add(i,i+n+t1,INF,cost1);//每天晚上可以送去快洗部,在地i+t1天早上收到餐巾 125 if(i+t2<=n) add(i,i+n+t2,INF,cost2);//每天晚上可以送去慢洗部,在地i+t2天早上收到餐巾 126 } 127 long long ans=MCMF(s,t,n+n+2); 128 cout<<ans<<endl; 129 }
以上是关于餐巾计划问题(费用流)的主要内容,如果未能解决你的问题,请参考以下文章