Description

一个餐厅在相继的N 天里,每天需用的餐巾数不尽相同。假设第i天需要ri块餐巾(i=1,2,…,N)。餐厅可以购买新的餐巾,每块餐巾的费用为p分;或者把旧餐巾送到快洗部,洗一块需m天,其费用为f 分;或者送到慢洗部,洗一块需n 天(n>m),其费用为s<f 分。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。

试设计一个算法为餐厅合理地安排好N 天中餐巾使用计划,使总的花费最小。

编程任务:编程找出一个最佳餐巾使用计划.

Input

第1 行有6 个正整数N,p,m,f,n,s。N 是要安排餐巾使用计划的天数;p 是每块新餐巾的费用;m 是快洗部洗一块餐巾需用天数;f 是快洗部洗一块餐巾需要的费用;n是慢洗部洗一块餐巾需用天数;s是慢洗部洗一块餐巾需要的费用。
接下来的N 行是餐厅在相继的N 天里,每天需用的餐巾数。

Output

程序运行结束时,将餐厅在相继的N 天里使用餐巾的最小总花费输出

Sample Input

3 10 2 3 3 2
5
6
7

Sample Output

145

Hint

题目中所有数字都不超过1000



看完题目很明显知道是一个最小费用最大流!

但是怎么建图呢?

二分图的思想来搞:X集合代表每个节点用过的餐巾,Y集合代表每个节点需要的餐巾(也就是拆点)

S-X:代表每个点用了多少:从S向每个Xi连一条容量为ri,费用为0的有向边

Y-T:代码每个点需要用多少:从每个Yi向T连一条容量为ri,费用为0的有向边


然后就是Y中需要使用的餐巾怎么来:

题目中的描述是有3种途径的

第一种:直接购买,那么是从S过来:从S向每个Yi连一条容量为无穷大,费用为p的有向边

第二种:慢洗:从每个Xi向Yi+n(i+n<=N)连一条容量为无穷大,费用为s的有向边

第三种:快洗:从每个Xi向Yi+m(i+m<=N)连一条容量为无穷大,费用为f的有向边


当然,可以不洗,留到之后再处理

从每个Xi向Xi+1(i+1<=N)连一条容量为无穷大,费用为0的有向边


建图建好了,之后,跑个模板就好了


#include<bits/stdc++.h>
using namespace std;

const int maxn=10000;
const int maxm=300000;
const int inf=0x3f3f3f3f;

struct Edge{
	int to,nxt,cap,flow,cost;
}edge[maxm];

int Head[maxn],tol,pre[maxn],dis[maxn];
bool vis[maxn];

int n,m,s,t,tot;
void init(){
	tol=0;
	memset(Head,-1,sizeof(Head));
}

void addedge(int u,int v,int cap,int cost){
	edge[tol].to=v;
	edge[tol].cap=cap;
	edge[tol].cost=cost;
	edge[tol].flow=0;
	edge[tol].nxt=Head[u];
	Head[u]=tol++;
	edge[tol].to=u;
	edge[tol].cap=0;
	edge[tol].cost=-cost;
	edge[tol].flow=0;
	edge[tol].nxt=Head[v];
	Head[v]=tol++;
}

bool spfa(int s,int t){
	queue<int> q;
	for(int i=0;i<tot;i++){
		dis[i]=inf;
		vis[i]=false;
		pre[i]=-1;
	}
	dis[s]=0;
	vis[s]=true;
	q.push(s);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=false;
		for(int i=Head[u];i!=-1;i=edge[i].nxt){
			int v=edge[i].to;
			if (edge[i].cap>edge[i].flow&&dis[v]>dis[u]+edge[i].cost){
				dis[v]=dis[u]+edge[i].cost;
				pre[v]=i;
				if (!vis[v]){
					vis[v]=true;
					q.push(v);
				}
			}
		}
	}
	if (pre[t]==-1) return false;
	return true;
}

int minCostMaxflow(int s,int t,int &cost){
	int flow=0;
	cost=0;
	while(spfa(s,t)){
		int Min=inf;
		for(int i=pre[t];i!=-1;i=pre[edge[i^1].to])
			if (Min>edge[i].cap-edge[i].flow)
				Min=edge[i].cap-edge[i].flow;
		for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]){
			edge[i].flow+=Min;
			edge[i^1].flow-=Min;
			cost+=edge[i].cost*Min;
		}
		flow+=Min;
	}
	return flow;
}

int main(){
	//freopen("input.txt","r",stdin);
	int N,pp,mm,ff,nn,ss,x;
	scanf("%d%d%d%d%d%d",&N,&pp,&mm,&ff,&nn,&ss);
	init();
	n=N;
	s=0;t=2*n+1;tot=2*n+2;
	for(int i=1;i<=n;i++){
		scanf("%d",&x);
		addedge(s,i,x,0);
		addedge(i+n,t,x,0);
		addedge(s,i+n,inf,pp);
		if (i<n) addedge(i,i+1,inf,0);
		if (i+mm<=n) addedge(i,i+mm+n,inf,ff);
		if (i+nn<=n) addedge(i,i+nn+n,inf,ss);
	}
	minCostMaxflow(s,t,x);
	printf("%d\n",x);
	return 0;
}