1. 程式人生 > >餐巾計劃問題(費用流)

餐巾計劃問題(費用流)

gif set false div 相同 splay style class space

餐巾計劃問題

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

餐巾計劃問題(費用流)