cogs 461 餐巾 题解
461. [网络流24题] 餐巾
★★★ 输入文件:napkin.in
输出文件:napkin.out
简单对比
时间限制:5 s 内存限制:128 MB
【问题描述】
一个餐厅在相继的N天里,第i天需要Ri块餐巾(i=l,2,…,N)。餐厅可以从三种途径获得餐巾。
(1)购买新的餐巾,每块需p分;
(2)把用过的餐巾送到快洗部,洗一块需m天,费用需f分(f<p)。如m=l时,第一天送到快洗部的餐巾第二天就可以使用了,送慢洗的情况也如此。
(3)把餐巾送到慢洗部,洗一块需n天(n>m),费用需s分(s<f)。
在每天结束时,餐厅必须决定多少块用过的餐巾送到快洗部,多少块送慢洗部。在每天开始时,餐厅必须决定是否购买新餐巾及多少,使洗好的和新购的餐巾之和满足当天的需求量Ri,并使N天总的费用最小。
【输入】
输入文件共 3 行,第 1 行为总天数;第 2 行为每天所需的餐巾块数;第 3 行为每块餐巾的新购费用 p ,快洗所需天数 m ,快洗所需费用 f ,慢洗所需天数 n ,慢洗所需费用 s 。
【输出】
一行,最小的费用
【样例】
napkin.in
3
3 2 4
10 1 6 2 3
napkin.out
64
【数据规模】
n<=200,Ri<=50
SOLUTION:
首先每天餐巾分为两种情况,新买的和原来的。每天作为一个点,由S向其连边,容量为ri,花费为0.
每天可以向T连边,容量为inf,花费为p,每天可购买餐巾无数次。将每天用过的餐巾再新建一层点,由于分配去快洗和慢洗的餐巾总数有限制,而并非分别有限制,所以快洗和慢洗不用分开讨论,放在一起即可,这层点再分别向T建边,容量为ri,花费为0,从而限制总容量。
使用快洗的餐巾,由i向i+m+t建边,容量为inf,花费为f;使用慢洗的餐巾,由i向i+n+t建边,花费为s。
但第i天洗完的餐巾也有可能再i+m以后的天中使用,所以再由i向i+1建边,容量为inf,花费为0,这样i+m以后天中就可以使用i+m天前洗完的餐巾了。
#include<cstdio> #include<cstring> #include<iostream> using namespace std; #define min(a,b) ((a)<(b)?(a):(b)) #define inf 99999999 int read() { int s=0,f=1; char ch=getchar(); while(ch>'9'||ch<'0') { if(ch=='-') { f=-1; } ch=getchar(); } while(ch>='0'&&ch<='9') { s=(s<<1)+(s<<3)+(ch^48); ch=getchar(); } return s*f; } int day[205],t,p,m,f,n,s,S,T,r[521],tot,pre[520],dis[520]; struct oo { int to,next,vv,cost; } c[160010]; void add(int x,int y,int z,int q) { c[tot].to=y; c[tot].vv=z; c[tot].cost=q; c[tot].next=r[x]; r[x]=tot++; } void build() { S=0; T=2*t+1; /*for(int i=1; i<=t; i++) { add(S,i,day[i],0); add(i,S,0,-0); add(i,i+t,inf,p); add(i+t,i,0,-p); if(i+m<=t) { add(i,i+t+m,inf,f); add(i+t+m,i,0,-f); } if(i+n<=t) { add(i,i+t+n,inf,s); add(i+t+n,i,0,-s); } if(i<t) { add(i,i+1,inf,0); add(i+1,i,0,0); } } for(int i=t+1; i<=2*t; i++) { add(i,T,day[i],0); add(T,i,0,-0); }*/ for(int i=1; i<=t; i++) { add(S,i,day[i],0); add(i,S,0,0); add(S,i+t,inf,p); add(i+t,S,0,-p); add(i+t,T,day[i],0); add(T,i+t,0,0); if(i+m<=t) { add(i,i+m+t,inf,f); add(i+m+t,i,0,-f); } if(i+n<=t) { add(i,i+n+t,inf,s); add(i+n+t,i,0,-s); } if(i!=t) { add(i,i+1,inf,0); add(i+1,i,0,0); } } } int queue[100005],head,tail,path[450]; bool vis[450]; bool bfs(int s,int t) { head=tail=0; memset(vis,0,sizeof(vis)); memset(pre,-1,sizeof(pre)); memset(dis,30,sizeof(dis)); dis[s]=0; queue[++tail]=s; while(head<tail) { int x=queue[++head]; vis[x]=0; for(int i=r[x]; ~i; i=c[i].next) { if(c[i].vv&&dis[c[i].to]>dis[x]+c[i].cost) { dis[c[i].to]=dis[x]+c[i].cost; pre[c[i].to]=x; path[c[i].to]=i; if(vis[c[i].to]==0){ queue[++tail]=c[i].to; vis[c[i].to]=1; } } } } if(pre[t]==-1) { return false; } else { return true; } } int dinic(int s,int t) { int f=0x7ffffff,ans=0; while(bfs(s,t)) { for(int i=t; i!=s; i=pre[i]) { if(c[path[i]].vv<f) { f=c[path[i]].vv; } } ans+=dis[t]*f; for(int i=t; i!=s; i=pre[i]) { c[path[i]].vv-=f; c[path[i]^1].vv+=f; } } return ans; } int main(){ freopen("napkin.in","r",stdin); freopen("napkin.out","w",stdout); memset(r,-1,sizeof(r)); t=read(); for(int i=1; i<=t; i++) { day[i]=read(); } p=read(); m=read(); f=read(); n=read(); s=read(); build(); int ans=dinic(S,T); printf("%d\n",ans); return 0; }