题目描述
一个餐厅在相继的 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 天里使用餐巾的最小总花费输出
思路:对于每天要用的餐巾,考虑它的来源,有可能是新购的,也有可能是快洗或慢洗后得到的,对于用过的餐巾,可以选择不作任何操作留到后一天,也可以快洗或者慢洗。 这样就可以把问题分成两部分考虑,剩下没处理的和每天需要的。对于第i天没处理的点ai,可以有源点得来,容量为每天需要的餐巾数,也可以由前一天得来,容量为无穷,对于每天需要的餐巾aj,可以有的源点得来,容量为需要的餐巾,费用为新购的费用,也可以由前m或n天快洗慢洗得来,费用为f,s。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; const long long maxn=5000; const long long maxm=1e6+5; const long long inf=1000000000; struct Edge{ Edge() {}; Edge(long long a,long long b,long long c,long long d) { v=a; f=b; w=c; nxt=d; } long long v,f,w,nxt; }; long long n,p,fn,fp,sn,sp,lmt; long long g[maxn+10]; Edge e[maxm*2+50]; long long nume; long long src,sink; void addedge(long long u,long long v,long long c,long long w) { e[++nume]=Edge(v,c,w,g[u]); g[u]=nume; e[++nume]=Edge(u,0,-w,g[v]); g[v]=nume; } queue<long long> que; bool inQue[maxn+10]; long long dist[maxn+10]; long long Prev[maxn+10],pree[maxn+10]; bool findpath() { while(!que.empty()) { que.pop(); } que.push(src); for(long long i=0;i<maxn+5;i++) dist[i]=inf; dist[src]=0; inQue[src]=true; while(!que.empty()) { long long u=que.front(); que.pop(); for(long long i=g[u];i;i=e[i].nxt) { if(e[i].f > 0 && dist[u] + e[i].w < dist[e[i].v]) { dist[e[i].v]=dist[u]+e[i].w; Prev[e[i].v]=u; pree[e[i].v]=i; if(!inQue[e[i].v]) { inQue[e[i].v]=true; que.push(e[i].v); } } } inQue[u]=false; } if(dist[sink]<inf) return true; else return false; } long long augment() { long long u=sink; long long delta=inf; while(u!=src) { if(e[pree[u]].f<delta) delta=e[pree[u]].f; u=Prev[u]; } u=sink; while(u!=src) { e[pree[u]].f-=delta; e[pree[u]^1].f+=delta; u=Prev[u]; } return dist[sink]*delta; } long long mincostflow() { long long cur=0; long long ans=0; while(findpath()) { cur+=augment(); if(cur>ans)ans=cur; } return ans; } long long r[maxn]; int main() { while(scanf("%lld",&n) != EOF) { nume=1; memset(g,0,sizeof(g)); for(long long i=1;i<=n;i++) { scanf("%lld",&r[i]); } scanf("%lld%lld%lld%lld%lld",&p,&fn,&fp,&sn,&sp); long long S=0,T=n+n+1; for(long long i=1;i<=n;i++) { addedge(S,i,r[i],0); addedge(i+n,T,r[i],0); addedge(S,i+n,inf,p); if(i+1<=n) addedge(i,i+1,inf,0); if(i+fn<=n) addedge(i,i+n+fn,inf,fp); if(i+sn<=n) addedge(i,i+n+sn,inf,sp); } src=S; sink=T; printf("%lld\n",mincostflow()); } }