一个餐厅在相继的
天里,每天需用的餐巾数不尽相同。假设第
天需要
块餐巾。餐厅可以购买新的餐巾,每块餐巾的费用为
分;或者把旧餐巾送到快洗部,洗一块需
天,其费用为
分;或者送到慢洗部,洗一块需
天,其费用为
分
。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
试设计一个算法为餐厅合理地安排好
天中餐巾使用计划,使总的花费最小。
数据范围:
显然是最小费用最大流
我们考虑拆点,把每一天拆成早上和晚上
源点
向第
天早上连一条流量为
,费用为
的边,表示每天早上购买若干条餐巾,每条
分
第
天早上向汇点
连一条流量为
,费用为
的边,表示这一天用了
块餐巾
源点
向第
天晚上连一条流量为
,费用为
的边,表示这一天结束后剩下
块脏毛巾
第
天晚上向第
天晚上连一条流量为
,费用为
的边,表示把若干块脏毛巾留到下一天晚上
第
天晚上向第
天早上连一条流量为
,费用为
的边,表示第
天晚上把若干块脏毛巾送到快洗部去洗,过
天后送回来。
第
天晚上向第
天早上连一条流量为
,费用为
的边,表示第
天晚上把若干块脏毛巾送到慢洗部去洗,过
天后送回来。
然后就是愉快的最小费用最大流啦!
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll inf=0x7fffffffffffffff;
int n,S,T,l,r,p,df,cf,ds,cs,a[4010],q[4010],inque[4010],pre[4010],tot=1,head[4010],nxt[3200010],to[3200010];
ll ans_flow,ans_cost,d[4010],flw[3200010],cst[3200010];
void add_edge(int u,int v,ll ct,ll fw){
nxt[++tot]=head[u];
to[tot]=v;
flw[tot]=fw;
cst[tot]=ct;
head[u]=tot;
return;
}
void Add_edge(int u,int v,ll ct,ll fw){
add_edge(u,v,ct,fw);
add_edge(v,u,-ct,0);
return;
}
bool spfa(){
for(int i=1;i<=(n<<1)+1;i++)
d[i]=inf;
l=r=d[S]=0;
q[r++]=S;
inque[S]=1;
while(l!=r){
int u=q[l];
l=(l+1)%5010;
inque[u]=0;
for(int i=head[u];i;i=nxt[i]){
int v=to[i];
ll ct=cst[i],fw=flw[i];
if(fw&&ct+d[u]<d[v]){
d[v]=d[u]+ct;
pre[v]=i;
if(!inque[v]){
inque[v]=1;
q[r]=v;
r=(r+1)%5010;
}
}
}
}
if(d[T]==inf)
return 0;
ll _flow=inf;
for(int i=T;i!=S;i=to[pre[i]^1])
_flow=min(_flow,flw[pre[i]]);
for(int i=T;i!=S;i=to[pre[i]^1]){
flw[pre[i]]-=_flow;
flw[pre[i]^1]+=_flow;
}
ans_flow+=_flow;
ans_cost+=d[T]*_flow;
return 1;
}
void MCMF(){
while(spfa());
return;
}
int main(){
scanf("%d%d%d%d%d%d",&n,&p,&df,&cf,&ds,&cs);
S=0;
T=(n<<1)+1;
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
Add_edge(i,T,0,x);
Add_edge(S,i+n,0,x);
}
for(int i=1;i<=n;i++){
Add_edge(S,i,p,inf);
if(i+1<=n)
Add_edge(i+n,i+n+1,0,inf);
if(i+df<=n)
Add_edge(i+n,i+df,cf,inf);
if(i+ds<=n)
Add_edge(i+n,i+ds,cs,inf);
}
MCMF();
printf("%lld",ans_cost);
return 0;
}