题目
题解
拆点,一个点表示一天开始,另一个点表示一天结束,具体建图方法见注释。
然后用EK算法跑费用流。
代码
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <queue> #include <stack> #include <vector> #include <map> #include <set> #include <utility> #include <cstdlib> using namespace std; typedef long long ll; const int maxn=5000; const int maxm=500000; const int inf=0x7fffffff; const ll llinf=0x7ffffffffffff; int n,m,s,t,day,tot=1,max_flow,p,t1,t2,p1,p2; ll min_cost; int r[maxn],head[maxn],pre[maxm],re[maxn]; //r[i]表示第i天需要的纸巾 ll d[maxn]; bool inq[maxn]; queue<int> q; struct edge{int to,nxt,cap,flow,cost;}e[maxm]; inline void add(int from,int to,int cap,int cost) { e[++tot].cap=cap; e[tot].to=to; e[tot].cost=cost; e[tot].nxt=head[from]; head[from]=tot; } inline int read() { int s1=0;char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') s1=(s1<<1)+(s1<<3)+(ch^48),ch=getchar(); return s1; } inline void make_graph() { s=maxn-1; t=maxn-2; for(int i=1;i<=day;i++) add(s,i<<1,inf,p),add(i<<1,s,0,-p); //早上买纸巾 for(int i=1;i<day;i++) add(i<<1|1,(i+1)<<1|1,inf,0),add((i+1)<<1|1,i<<1|1,0,0); //把脏纸巾从第一天晚上保留到第二天晚上,注意区分干净纸巾和脏纸巾 for(int i=1;i<=day;i++) add(s,i<<1|1,r[i],0),add(i<<1|1,s,0,0); //晚上得到脏纸巾 for(int i=1;i<=day;i++) add(i<<1,t,r[i],0),add(t,i<<1,0,0); //每天早上向汇点提供纸巾,流满时表示够用 for(int i=1;i<=day;i++) if(i+t1<=day) add(i<<1|1,(i+t1)<<1,inf,p1),add((i+t1)<<1,i<<1|1,0,-p1); //快洗,晚上开始洗,早上收到 for(int i=1;i<=day;i++) if(i+t2<=day) add(i<<1|1,(i+t2)<<1,inf,p2),add((i+t2)<<1,i<<1|1,0,-p2); //慢洗 } inline bool spfa() { for(int i=1;i<maxn;i++) d[i]=llinf; //注意不要写成<=,否则会占用非法空间 d[s]=0; re[s]=inf; q.push(s); inq[s]=1; while(q.size()) { int x=q.front(); q.pop(); inq[x]=0; //注意别忘了 for(int i=head[x];i;i=e[i].nxt) { int y=e[i].to; if(e[i].cap>e[i].flow&&d[y]>d[x]+(ll)e[i].cost) { d[y]=d[x]+(ll)e[i].cost; re[y]=min(re[x],e[i].cap-e[i].flow); pre[y]=i; if(inq[y]) continue; inq[y]=1; q.push(y); } } } return d[t]<llinf; } inline void upd() { max_flow+=re[t]; min_cost+=(ll)re[t]*d[t]; int x=t; while(x!=s) { int i=pre[x]; e[i].flow+=re[t]; e[i^1].flow-=re[t]; x=e[i^1].to; } } inline void EK() { while(spfa()) upd(); printf("%lld\n",min_cost); } int main() { //freopen("test2019.in","r",stdin); //freopen("test2019.out","w",stdout); day=read(); for(int i=1;i<=day;i++) r[i]=read(); p=read(),t1=read(),p1=read(),t2=read(),p2=read(); make_graph(); EK(); return 0; }