容易看出这是显然的费用流模型。
把每天需要的餐巾数作为限制。需要将天数拆点,x’表示每天需要的餐巾,x’’表示每天用完的餐巾。所以加边 (s,x',INF,0),(x'',t,INF,0).
餐巾可以新买。所以需要加边(s,x'',INF,f)。
没用完餐巾可以留到下一天,所以加边(x',x+1',INF,0).
送往快洗店,加边(x',x+a+1'',INF,fa). 送往慢洗店,加边(x',x+b+1'',INF,fb).
跑一遍费用流即可。由于该图是一种特殊的结构,类二分图结构。用ZKW费用流可以快速出解。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi 3.1415926535 # define eps 1e-9 # define MOD 100000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; int Scan() { int res=0, flag=0; char ch; if((ch=getchar())=='-') flag=1; else if(ch>='0'&&ch<='9') res=ch-'0'; while((ch=getchar())>='0'&&ch<='9') res=res*10+(ch-'0'); return flag?-res:res; } void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=2005; //Code begin... struct Edge{ int to, next, cap, flow, cost; Edge(int _to=0, int _next=0, int _cap=0, int _flow=0, int _cost=0): to(_to), next(_next), cap(_cap), flow(_flow), cost(_cost){} }edge[50005]; struct ZKW_MinCostMaxFlow{ int head[50005], tot, cur[50005], dis[50005], ss, tt, n, min_cost, max_flow; bool vis[50005]; void init(){tot=0; mem(head,-1);} void addedge(int u, int v, int cap, int cost){ edge[tot]=Edge(v,head[u],cap,0,cost); head[u]=tot++; edge[tot]=Edge(u,head[v],0,0,-cost); head[v]=tot++; } int aug(int u, int flow){ if (u==tt) return flow; vis[u]=true; for (int i=cur[u]; i!=-1; i=edge[i].next) { int v=edge[i].to; if (edge[i].cap>edge[i].flow&&!vis[v]&&dis[u]==dis[v]+edge[i].cost) { int tmp=aug(v,min(flow,edge[i].cap-edge[i].flow)); edge[i].flow+=tmp; edge[i^1].flow-=tmp; cur[u]=i; if (tmp) return tmp; } } return 0; } bool modify_label(){ int d=INF; FO(u,0,n) if (vis[u]) for (int i=head[u]; i!=-1; i=edge[i].next) { int v=edge[i].to; if (edge[i].cap>edge[i].flow&&!vis[v]) d=min(d,dis[v]+edge[i].cost-dis[u]); } if (d==INF) return false; FO(i,0,n) if (vis[i]) vis[i]=false, dis[i]+=d; return true; } PII mincostmaxflow(int start, int end, int nn){ ss=start, tt=end, n=nn; min_cost=max_flow=0; FO(i,0,n) dis[i]=0; while (1) { FO(i,0,n) cur[i]=head[i]; while (1) { FO(i,0,n) vis[i]=false; int tmp=aug(ss,INF); if (tmp==0) break; max_flow+=tmp; min_cost+=tmp*dis[ss]; } if (!modify_label()) break; } return mp(min_cost,max_flow); } }solve; int val[N]; int main () { int n,a,b,fa,fb,f; scanf("%d%d%d%d%d%d",&n,&a,&b,&f,&fa,&fb); solve.init(); FOR(i,1,n) scanf("%d",val+i), solve.addedge(0,i,val[i],0), solve.addedge(0,i+n,INF,f), solve.addedge(i+n,2*n+1,val[i],0); FOR(i,1,n) { if (i<n) solve.addedge(i,i+1,INF,0); if (i<n-a) solve.addedge(i,i+n+a+1,INF,fa); if (i<n-b) solve.addedge(i,i+n+b+1,INF,fb); } printf("%d ",solve.mincostmaxflow(0,2*n+1,2*n+2).first); return 0; }