把每一天拆成早上(i)和晚上(i+n),每天晚上会收到用过的脏毛巾,早上会从快洗部和慢洗部或通过购买得到新毛巾。
构图:
1.从源点向每一天晚上建流量为当天需要的餐巾数ri,费用为0的边,表示每天晚上会有ri条用过的餐巾。
2.从每一天早上向汇点建流量为当天需要的餐巾数ri,费用为0的边,表示每天白天需要提供ri条干净的餐巾,流满时餐巾够用。
3.从每一天晚上向下一天晚上建流量为INF,费用为0的边,表示每一天晚上的脏餐巾可以留到下一天晚上再处理。
4.从每一天晚上向当天+快洗需要的天数建流量为INF,费用为快洗价格的边,表示每天晚上可以送餐巾去快洗部,在当天+快洗需要的天数那一天收到干净餐巾。
5.从每一天晚上向当天+慢洗需要的天数建流量为INF,费用为慢洗价格的边,表示每天晚上可以送餐巾去慢洗部,在当天+慢洗需要的天数那一天收到干净餐巾。
6.从源点向每一天早上建边,流量为INF,费用为购买价格,表示每天早上可以购买餐巾。
后四条建边时注意天数不能超过n。
建图后跑费用流。
Code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;
const int INF=0x3f3f3f3f;
struct node{int x,y,c,d,next,other;}a[24010];
int first[4010],f[4010],pre[4010],pos[4010],p[4010];
int n,m,t1,m1,t2,m2,st,ed,len;
bool v[4010];
queue<int> q;
void ins(int x,int y,int c,int d)
{
a[++len]=(node){x,y,c,d,first[x],len+1};first[x]=len;
a[++len]=(node){y,x,0,-d,first[y],len-1};first[y]=len;
}
bool spfa()
{
memset(f,INF,sizeof(f));f[st]=0;
memset(v,false,sizeof(v));v[st]=true;
p[st]=INF;
q.push(st);
while(!q.empty())
{
int x=q.front();
for(int i=first[x];i;i=a[i].next)
{
int y=a[i].y;
if(a[i].c>0 && f[y]>f[x]+a[i].d)
{
f[y]=f[x]+a[i].d;
pre[y]=i;
pos[y]=x;
p[y]=min(p[x],a[i].c);
if(!v[y])
{
v[y]=true;
q.push(y);
}
}
}
v[x]=false;
q.pop();
}
return f[ed]<INF;
}
ll flow()
{
ll ans=0;
while(spfa())
{
ans+=f[ed]*p[ed];
for(int i=ed;i!=st;i=pos[i])
{
a[pre[i]].c-=p[ed];
a[a[pre[i]].other].c+=p[ed];
}
}
return ans;
}
int main()
{
scanf("%d",&n);
st=2*n+1;ed=st+1;
memset(first,len=0,sizeof first);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
ins(st,i+n,x,0);
ins(i,ed,x,0);
}
scanf("%d %d %d %d %d",&m,&t1,&m1,&t2,&m2);
for(int i=1;i<=n;i++)
{
if(i+1<=n) ins(i+n,i+n+1,INF,0);
if(i+t1<=n) ins(i+n,i+t1,INF,m1);
if(i+t2<=n) ins(i+n,i+t2,INF,m2);
ins(st,i,INF,m);
}
printf("%lld",flow());
}