网络流24题 餐巾计划(DCOJ8008)
题目描述
一个餐厅在相继的 n nn 天里,每天需用的餐巾数不尽相同。假设第 i ii 天需要 ri r_iri 块餐巾。餐厅可以购买新的餐巾,每块餐巾的费用为 P PP 分;或者把旧餐巾送到快洗部,洗一块需 M MM 天,其费用为 F FF 分;或者送到慢洗部,洗一块需 N NN 天,其费用为 S SS 分(S<F S < FS<F)。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
试设计一个算法为餐厅合理地安排好 n nn 天中餐巾使用计划,使总的花费最小。
输入格式
第 1 11 行有 6 66 个正整数 n nn、P PP、M MM、F FF、N NN、S SS。
n nn 是要安排餐巾使用计划的天数,P PP 是每块新餐巾的费用,M MM 是快洗部洗一块餐巾需用天数,F FF 是快洗部洗一块餐巾需要的费用,N NN 是慢洗部洗一块餐巾需用天数,S SS 是慢洗部洗一块餐巾需要的费用。
接下来的 n nn 行是餐厅在相继的 n nn 天里,每天需用的餐巾数。
输出格式
输出餐厅在相继的 n nn 天里使用餐巾的最小总花费。
样例
样例输入
3 10 2 3 3 2
5
6
7
样例输出
145
数据范围与提示
1≤n≤1000 1 \leq n \leq 10001≤n≤1000
这是我碰到的第一道想了至少二十分钟才理解的网络流题。
主要是要把当天要用的和当天用过的(没洗的)分开来,弄成不同的两个点,然后就可以从某天用过没洗的点向N天或M天后要用的点连边,费用为洗衣费用。
从源点向每个当天用过的(没洗的)的点连边,最大流量为当天要用的值。
从每个当天要用的的点向汇点连边,最大流量为当天要用的值。
从每个第i天用过的(没洗的)的点向第i+1天用过的(没洗的)的点连边,最大流量为INF。
从源点向每个当天要用的的点连边,边长INF,费用为P(购买费用)。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=2000+10,maxm=6*maxn+10,INF=0x3f3f3f3f; int day,P,M,F,N,R,S,T; int aa;char cc; int read() { aa=0;cc=getchar(); while(cc<'0'||cc>'9') cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa; } struct Node{ int x,y,cap,flow,w; Node(){} Node(int x,int y,int cap,int w):x(x),y(y),cap(cap),w(w){} }node[2*maxm]; int fir[maxn],nxt[2*maxm],e=1; void add(int x,int y,int z,int w) { node[++e]=Node(x,y,z,w); nxt[e]=fir[x];fir[x]=e; node[++e]=Node(y,x,0,-w); nxt[e]=fir[y];fir[y]=e; } int from[maxn],zz[maxn],dis[maxn]; bool vis[maxn]; bool spfa() { int s=1,t=0,x,y,z; memset(dis,0x3f3f3f3f,sizeof(dis)); memset(zz,0,sizeof(zz)); zz[++t]=S;vis[S]=1;dis[S]=0; while(s<=t) { x=zz[s%maxn]; for(y=fir[x];y;y=nxt[y]) { z=node[y].y; if(node[y].flow>=node[y].cap||dis[z]<=dis[x]+node[y].w) continue; dis[z]=dis[x]+node[y].w;from[z]=y; if(!vis[z]) { vis[z]=1; t++; zz[t%maxn]=z; } } s++;vis[x]=0; } return dis[T]!=INF; } int now,rs1=0,rs2=0; int MCMF() { while(spfa()) { now=INF; for(int i=T;i!=S;i=node[from[i]].x) now=min(now,node[from[i]].cap-node[from[i]].flow); for(int i=T;i!=S;i=node[from[i]].x) { node[from[i]].flow+=now; node[from[i]^1].flow-=now; rs2+=node[from[i]].w*now; } } return rs2; } int main() { day=read();P=read();M=read();F=read();N=read();R=read(); int x; S=2*day+1;T=S+1; for(int i=1;i<=day;++i) { add(S,i+day,INF,P); if(i+1<=day) add(i,i+1,INF,0); if(i+M<=day) add(i,i+M+day,INF,F); if(i+N<=day) add(i,i+N+day,INF,R); } for(int i=1;i<=day;++i) { x=read(); add(S,i,x,0);add(i+day,T,x,0); } printf("%d",MCMF()); return 0; }