题目描述 Description
一个餐厅在相继的 N 天里,每天需用的餐巾数不尽相同。假设第 i 天需要 ri块餐巾(i=1,2,…,N)。餐厅可以购买新的餐巾,每块餐巾的费用为 p 分;或者把旧餐巾送到快洗部,洗一块需 m 天,其费用为 f 分;或者送到慢洗部,洗一块需 n 天(n>m),其费用为 s<f 分。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
试设计一个算法为餐厅合理地安排好 N 天中餐巾使用计划,使总的花费最小。
编程找出一个最佳餐巾使用计划.
输入描述 Input Description
第 1 行有 6 个正整数 N,p,m,f,n,s。N 是要安排餐巾使用计划的天数;p 是每块新餐巾的费用;m 是快洗部洗一块餐巾需用天数;f 是快洗部洗一块餐巾需要的费用;n 是慢洗部洗一块餐巾需用天数;s 是慢洗部洗一块餐巾需要的费用。接下来的 N 行是餐厅在相继的 N 天里,每天需用的餐巾数。
输出描述 Output Description
将餐厅在相继的 N 天里使用餐巾的最小总花费输出
样例输入 Sample Input
3 10 2 3 3 2
5
6
7
样例输出 Sample Output
145
题目分析
此题用最小费用流解决
题目所说的每天需用ri块餐巾,我们可以这么理解,把一天拆成两个点Xi和Yi(上午和下午),一天既然需要用ri块餐巾,则必定会消耗ri块,所以我们把Xi表示为这一天接受到的干净的餐巾数,Yi表示为消耗的餐巾数,那么就好建边了.
从Xi-->X(i+1)建一条(inf,0)的边,表示此边容量无穷大,费用为0,理解为前一天可以把没用完的餐巾留到后一天
从源点S-->每个Xi建一条(inf,p)的边,表示无论如何你至少可以通过买餐巾来达到需求
从源点S-->每个Yi建一条(ri,0)的边
从每个Xi-->汇点T点建一条(ri,0)的边
从每个Yi-->X(i+m)建一条(inf,f)的边表示每天可以送餐巾到快洗部,费用为f
同理从每个Yi-->X(i+n)建一条(inf,s)的边表示每天可以送餐巾到慢洗部,费用为s
然后直接跑费用流模板
上代码
1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cmath> 5 #include<cstring> 6 #include<algorithm> 7 #include<cstdlib> 8 #include<queue> 9 #define in(i) (i=read()) 10 #define inf (2147483647) 11 using namespace std; 12 typedef long long lol;//就是要注意一点因为最大值赋的是int类型最大值,所以有乘法运算就会爆int,so开long long 13 lol read() 14 { 15 lol ans=0,f=1; 16 char i=getchar(); 17 while(i<‘0‘||i>‘9‘) 18 { 19 if(i==‘-‘) f=-1; 20 i=getchar(); 21 } 22 while(i>=‘0‘&&i<=‘9‘) 23 { 24 ans=(ans<<3)+(ans<<1)+i-‘0‘; 25 i=getchar(); 26 } 27 return ans*f; 28 } 29 struct edge 30 { 31 lol to,next,cap,v; 32 }e[40010]; 33 lol head[40010]; 34 lol lev[4010],vis[4010]; 35 lol len=1; 36 void add(lol a,lol b,lol c,lol d) 37 { 38 e[++len].to=b; 39 e[len].next=head[a]; 40 e[len].cap=c; 41 e[len].v=d; 42 head[a]=len; 43 } 44 lol pre[3010]; 45 bool bfs(lol s,lol t) 46 { 47 queue<lol>q; 48 memset(lev,127/3,sizeof(lev)); 49 q.push(s); 50 lev[s]=0; 51 while(!q.empty()) 52 { 53 lol x=q.front(); 54 q.pop(); 55 for(lol i=head[x];i;i=e[i].next) 56 { 57 lol to=e[i].to; 58 if(e[i].cap>0&&lev[to]>lev[x]+e[i].v) 59 { 60 lev[to]=lev[x]+e[i].v; 61 pre[to]=i; 62 q.push(to); 63 } 64 } 65 } 66 if(lev[t]<lev[0]) return 1; 67 return 0; 68 } 69 lol change(lol s,lol t) 70 { 71 lol x=t,flow=inf,ans=0; 72 while(x!=s) 73 { 74 flow=min(flow,e[pre[x]].cap); 75 x=e[pre[x]^1].to; 76 } 77 x=t; 78 while(x!=s) 79 { 80 e[pre[x]].cap-=flow; 81 e[pre[x]^1].cap+=flow; 82 ans+=flow*e[pre[x]].v; 83 x=e[pre[x]^1].to; 84 } 85 return ans; 86 } 87 int main() 88 { 89 lol tot=0; 90 lol n,r; 91 lol p,a,f,b,s; 92 in(n); 93 for(lol i=1;i<=n;i++) 94 { 95 in(r); 96 add(i,(n<<1)+2,r,0);//Xi-->T 97 add((n<<1)+2,i,0,0); 98 add((n<<1)+1,i+n,r,0);//S-->Yi 99 add(i+n,(n<<1)+1,0,0); 100 } 101 in(p); 102 for(lol i=1;i<=n;i++) 103 { 104 add((n<<1)+1,i,inf,p);//S-->Xi,买餐巾 105 add(i,(n<<1)+1,0,-p); 106 } 107 for(lol i=1;i<n;i++) 108 { 109 add(i,i+1,inf,0);//前一天留到第二天 110 add(i+1,i,0,0); 111 } 112 in(a);in(f); 113 for(lol i=1;i<=n-a;i++) 114 { 115 add(i+n,i+a,inf,f);//送到快洗部 116 add(i+a,i+n,0,-f); 117 } 118 in(b);in(s); 119 for(lol i=1;i<=n-b;i++) 120 { 121 add(i+n,i+b,inf,s);//送到慢洗部 122 add(i+b,i+n,0,-s); 123 } 124 while(bfs((n<<1)+1,(n<<1)+2)) 125 { 126 tot+=change((n<<1)+1,(n<<1)+2); 127 } 128 cout<<tot<<endl; 129 return 0; 130 }