记录编号 361028 评测结果 AAAAAAAAAAAA
题目名称 [网络流24题] 餐巾 最终得分 100
用户昵称 GravatarFoolMike 是否通过 通过
代码语言 C++ 运行时间 0.028 s
提交时间 2017-01-02 19:06:33 内存使用 4.98 MiB
显示代码纯文本
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1e5+10;
struct edge{
	int f,t,g,l,o;
	edge(int F=0,int T=0,int G=0,int L=0,int O=0){
		f=F;t=T;g=G;l=L;o=O;
	}
}w[N];
int n,df,cf,ds,cs,p,a[N],head[N],tail[N],next[N];
void add(int f,int t,int g,int l){
	static int cnt=0;
	++cnt;w[cnt]=edge(f,t,g,l,cnt+1);
	if (!head[f]) head[f]=tail[f]=cnt;
		else tail[f]=next[tail[f]]=cnt;
	++cnt;w[cnt]=edge(t,f,0,-l,cnt-1);
	if (!head[t]) head[t]=tail[t]=cnt;
		else tail[t]=next[tail[t]]=cnt;
}
//第i天餐巾的入口为i,出口(即使用过的)为i+n,流量为餐巾的流通。
//第i天消耗的餐巾为a[i],等价于经过i->i+n的流为a[i] 
//那么该图上的最小费用可行流即答案 
queue<int> Q;
int s,t,S,T,ans,dis[N],flow[N],from[N];
bool inque[N];
bool spfa(){
	for (int i=S;i<=T;i++) dis[i]=1e9;
	dis[S]=0;flow[S]=1e9;
	Q.push(S);
	while (!Q.empty()){
		int v=Q.front();Q.pop();
		inque[v]=0;
		for (int i=head[v];i;i=next[i])
		if (w[i].g&&dis[w[i].t]>dis[v]+w[i].l){
			int u=w[i].t;
			dis[u]=dis[v]+w[i].l;
			from[u]=i;
			flow[u]=min(flow[v],w[i].g);
			if (!inque[u]) inque[u]=1,Q.push(u);
		}
	}
	if (dis[T]==1e9) return 0;
	int df=flow[T];ans+=dis[T]*df;
	for (int i=from[T];i;i=from[w[i].f])
		w[i].g-=df,w[w[i].o].g+=df;
	return 1;
}
int main()
{
	freopen("napkin.in","r",stdin);
	freopen("napkin.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	scanf("%d%d%d%d%d",&p,&df,&cf,&ds,&cs);
	s=n*2+1;t=n*2+2;//原图的源汇点 
	add(t,s,1e9,0);
	S=0;T=n*2+3;//新图的源汇点 
	for (int i=1;i<=n;i++){
		add(s,i,1e9,p);//买餐巾 
		//使用餐巾 
		//add(i,i+n,a[i],0);//原图边 
		add(S,i+n,a[i],0);//新图边 
		add(i,T,a[i],0);
		add(i+n,t,1e9,0);//浪费餐巾 
		if (i+df<=n) add(i+n,i+df,1e9,cf);//快洗 
		if (i+ds<=n) add(i+n,i+ds,1e9,cs);//慢洗 
		if (i<n) add(i,i+1,1e9,0);//留着明天用 
	}
	while (spfa());
	printf("%d\n",ans);
	return 0;
}