[网络流24题]餐巾计划问题
Description
一个餐厅在相继的$N$天里,每天需用的餐巾数不尽相同,假设第$i$天需要$r_i$块餐巾$(i\in[1,N])$.
餐厅可以购买新的餐巾,每块餐巾的费用为$p$分;或者把旧餐巾送到快洗部,洗一块需$m$天,其费用为$f$分;或者送到慢洗部,洗一块需$n$天$(n>m)$,其费用为$w(w<f)$分.
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗.但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量.
试为餐厅合理地安排好$N$天中餐巾使用计划,使总的花费最小.
Input
第$1$行有$6$个正整数$N,p,m,f,n,w.N$是要安排餐巾使用计划的天数;$p$是每块新餐巾的费用;$m$是快洗部洗一块餐巾需用天数;$f$是快洗部洗一块餐巾需要的费用;$n$是慢洗部洗一块餐巾需用天数;$w$是慢洗部洗一块餐巾需要的费用.
接下来的$N$行是餐厅在相继的$N$天里,每天需用的餐巾数.
Output
一行一个整数餐厅在相继的$N$天里使用餐巾的最小总花费.
Sample Input
3 10 2 3 3 2
5
6
7
Sample Output
145
HINT
$n\;\leq\;1000$
Solution
把第$i$天拆成两个点$x_i,y_i$,分别表示当天用完的和需要的.
从$s$向$x_i$连一条容量为$r_i$,费用为$0$的有向边.
从$y_i$向$t$连一条容量为$r_i$,费用为$0$的有向边.
从$x_i$向$x_{i+1}$连一条容量为$+\infty$,费用为$0$的有向边.(不在第$i$天洗的餐巾)
从$x_i$向$y_{i+m}$连一条容量为$+\infty$,费用为$f$的有向边.
从$x_i$向$y_{i+n}$连一条容量为$+\infty$,费用为$w$的有向边.
求最小费用最大流.
#include<cmath> #include<ctime> #include<queue> #include<stack> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 2005 #define M 20005 #define INF 1000000000 using namespace std; struct graph{ int nxt,to,f,w; }e[M]; struct edge{ int e,v; }pre[N]; int g[N],dis[N],n,p,s,t,d1,w1,d2,w2,cnt=1; bool inq[N]; queue<int> q; inline void addedge(int x,int y,int f,int w){ e[++cnt].nxt=g[x];g[x]=cnt; e[cnt].to=y;e[cnt].f=f;e[cnt].w=w; } inline void adde(int x,int y,int f,int w){ addedge(x,y,f,w);addedge(y,x,0,-w); } inline bool spfa(int u){ for(int i=1;i<=t;++i){ dis[i]=INF;inq[i]=false; } q.push(u);dis[u]=0;inq[u]=true; while(!q.empty()){ u=q.front();q.pop();inq[u]=false; for(int i=g[u];i;i=e[i].nxt) if(e[i].f>0&&dis[u]+e[i].w<dis[e[i].to]){ dis[e[i].to]=dis[u]+e[i].w; pre[e[i].to].e=i;pre[e[i].to].v=u; if(!inq[e[i].to]){ q.push(e[i].to);inq[e[i].to]=true; } } } return dis[t]<INF; } inline int mf(){ int ret=0,d; while(spfa(s)){ d=INF; for(int i=t;i!=s;i=pre[i].v) d=min(d,e[pre[i].e].f); ret+=d*dis[t]; for(int i=t;i!=s;i=pre[i].v){ e[pre[i].e].f-=d; e[pre[i].e^1].f+=d; } } return ret; } inline void Aireen(){ scanf("%d%d%d%d%d%d",&n,&p,&d1,&w1,&d2,&w2); s=(n<<1)+1;t=s+1; for(int i=1,r;i<=n;++i){ scanf("%d",&r); adde(s,i+n,INF,p); adde(s,i,r,0); adde(i+n,t,r,0); } for(int i=1;i<=n;++i){ if(i<n) adde(i,i+1,INF,0); if(i+d1<=n) adde(i,i+d1+n,INF,w1); if(i+d2<=n) adde(i,i+d2+n,INF,w2); } printf("%d\n",mf()); } int main(){ freopen("napk.in","r",stdin); freopen("napk.out","w",stdout); Aireen(); fclose(stdin); fclose(stdout); return 0; }