关键是要想到建立二分图,这个确实一开始没想到。
重点是把当天需要的和当天剩下的给分开。这样就可以建图了。
1.对于当天需要的,跟源点连边,流量为
ri
,花费为p。跟汇点连边,花费为0,流量为
ri
。
2.对于当天剩下的,跟源点相连,流量为
ri
,因为当天的肯定会剩下的,然后对于第i天,向第i+1天连边,花费0,流量为inf。因为当天的可以放到第二天。然后对于第i天剩下的,可以向第i+day天的需要的点连边,表示洗好的。花费为相应的店的花费,流量为inf。
然后跑最小费用最大流就可以了。
因为数据范围的问题,wa了好几发QAQ。
#include <bits/stdc++.h>
using namespace std;
const int MAXN=10000+5;
const int inf=1e9+7;
int n,p,day1,cost1,day2,cost2;
int s,e;
int cnt,head[MAXN];
struct node
{
int u,v,w,f,next;
} edge[1002005];
void init()
{
cnt=0;
for(int i=0; i<=e; ++i)
{
head[i]=-1;
}
}
void add(int u,int v,int w,int f)
{
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].f=f;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].u=v;
edge[cnt].v=u;
edge[cnt].w=-w;
edge[cnt].f=0;
edge[cnt].next=head[v];
head[v]=cnt++;
}
bool vis[MAXN];
int dis[MAXN],pre[MAXN];
bool spfa()
{
int i;
for(i = 0; i <= e; ++i)
{
dis[i]=inf;
pre[i]=-1;
}
queue<int>q;
q.push(s);
dis[s]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(i=head[u]; i!=-1; i=edge[i].next)
{
int v=edge[i].v;
int w=edge[i].w;
int f=edge[i].f;
if(f>0&&dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
pre[v]=i;
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
if(pre[e]==-1)return 0;
return 1;
}
int get_mincost()
{
int min_cost = 0,max_flow=0;
while(spfa())
{
int p=pre[e];
int flow=inf;
while(p!=-1)
{
flow=min(flow,edge[p].f);
p=pre[edge[p].u];
}
max_flow+=flow;
min_cost += flow*dis[e];
p=pre[e];
while(p!=-1)
{
edge[p].f-=flow;
edge[p^1].f+=flow;
p=pre[edge[p].u];
}
}
return min_cost;
}
int need[MAXN];
int main()
{
scanf("%d%d%d%d%d%d",&n,&p,&day1,&cost1,&day2,&cost2);
for(int i = 1; i <= n; ++i)scanf("%d",&need[i]);
s = 0, e = n<<1|1;
init();
for(int i = 1; i <= n; ++i)
{
add(s,i,0,need[i]);
add(i+n,e,0,need[i]);
add(s,i+n,p,need[i]);
}
for(int i = 2; i <= n; ++i)add(i-1,i,0,inf);
//快洗
for(int i = 1; i <= n-day1; ++i)add(i,i+day1+n,cost1,inf);
//慢洗
for(int i = 1; i <= n-day2; ++i)add(i,i+day2+n,cost2,inf);
printf("%d\n",get_mincost());
return 0;
}