餐巾计划问题(费用流)

餐巾计划问题

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 天里使用餐巾的最小总花费输出

 

输入输出样例

输入样例#1: 
3
1 7 5 
11 2 2 3 1
输出样例#1: 
134

说明

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

 

posted on 2018-10-25 11:43  Fighting_sh  阅读(335)  评论(0编辑  收藏  举报

导航