cogs 461 餐巾 题解

461. [网络流24题] 餐巾

★★★   输入文件:napkin.in   输出文件:napkin.out   简单对比
时间限制:5 s   内存限制:128 MB

【问题描述】

 

 一个餐厅在相继的N天里,第i天需要Ri块餐巾(i=l,2,…,N)。餐厅可以从三种途径获得餐巾。

    (1)购买新的餐巾,每块需p分;

    (2)把用过的餐巾送到快洗部,洗一块需m天,费用需f分(f<p)。如m=l时,第一天送到快洗部的餐巾第二天就可以使用了,送慢洗的情况也如此。

    (3)把餐巾送到慢洗部,洗一块需n天(n>m),费用需s分(s<f)。

    在每天结束时,餐厅必须决定多少块用过的餐巾送到快洗部,多少块送慢洗部。在每天开始时,餐厅必须决定是否购买新餐巾及多少,使洗好的和新购的餐巾之和满足当天的需求量Ri,并使N天总的费用最小。

 

 

【输入】

输入文件共 3 行,第 1 行为总天数;第 2 行为每天所需的餐巾块数;第 3 行为每块餐巾的新购费用 p ,快洗所需天数 m ,快洗所需费用 f ,慢洗所需天数 n ,慢洗所需费用 s 。

【输出】

一行,最小的费用

【样例】

napkin.in


3 2 4 
10 1 6 2 3

napkin.out

64

【数据规模】

n<=200,Ri<=50

SOLUTION:

    首先每天餐巾分为两种情况,新买的和原来的。每天作为一个点,由S向其连边,容量为ri,花费为0.

      每天可以向T连边,容量为inf,花费为p,每天可购买餐巾无数次。将每天用过的餐巾再新建一层点,由于分配去快洗和慢洗的餐巾总数有限制,而并非分别有限制,所以快洗和慢洗不用分开讨论,放在一起即可,这层点再分别向T建边,容量为ri,花费为0,从而限制总容量。

   使用快洗的餐巾,由i向i+m+t建边,容量为inf,花费为f;使用慢洗的餐巾,由i向i+n+t建边,花费为s。

   但第i天洗完的餐巾也有可能再i+m以后的天中使用,所以再由i向i+1建边,容量为inf,花费为0,这样i+m以后天中就可以使用i+m天前洗完的餐巾了。


#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define min(a,b) ((a)<(b)?(a):(b))
#define inf 99999999
int read() {
	int s=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0') {
		if(ch=='-') {
			f=-1;
		}
		ch=getchar();
	}
	while(ch>='0'&&ch<='9') {
		s=(s<<1)+(s<<3)+(ch^48);
		ch=getchar();
	}
	return s*f;
}
int day[205],t,p,m,f,n,s,S,T,r[521],tot,pre[520],dis[520];
struct oo {
	int to,next,vv,cost;
} c[160010];
void add(int x,int y,int z,int q) {
	c[tot].to=y;
	c[tot].vv=z;
	c[tot].cost=q;
	c[tot].next=r[x];
	r[x]=tot++;
}
void build() {
	S=0;
	T=2*t+1;
	/*for(int i=1; i<=t; i++) {
		add(S,i,day[i],0);
		add(i,S,0,-0);
		add(i,i+t,inf,p);
		add(i+t,i,0,-p);
		if(i+m<=t) {
			add(i,i+t+m,inf,f);
			add(i+t+m,i,0,-f);
		}
		if(i+n<=t) {
			add(i,i+t+n,inf,s);
			add(i+t+n,i,0,-s);
		}
		if(i<t) {
			add(i,i+1,inf,0);
			add(i+1,i,0,0);
		}
	}
	for(int i=t+1; i<=2*t; i++) {
		add(i,T,day[i],0);
		add(T,i,0,-0);
	}*/
	for(int i=1; i<=t; i++) {
		add(S,i,day[i],0);
		add(i,S,0,0);
		add(S,i+t,inf,p);
		add(i+t,S,0,-p);
		add(i+t,T,day[i],0);
		add(T,i+t,0,0);
		if(i+m<=t) {
			add(i,i+m+t,inf,f);
			add(i+m+t,i,0,-f);
		}
		if(i+n<=t) {
			add(i,i+n+t,inf,s);
			add(i+n+t,i,0,-s);
		}
		if(i!=t) {
			add(i,i+1,inf,0);
			add(i+1,i,0,0);
		}
	}
}
int queue[100005],head,tail,path[450];
bool vis[450];
bool bfs(int s,int t) {
	head=tail=0;
	memset(vis,0,sizeof(vis));
	memset(pre,-1,sizeof(pre));
	memset(dis,30,sizeof(dis));
	dis[s]=0;
	queue[++tail]=s;
	while(head<tail) {
		int x=queue[++head];
		vis[x]=0;
		for(int i=r[x]; ~i; i=c[i].next) {
			if(c[i].vv&&dis[c[i].to]>dis[x]+c[i].cost) {
				dis[c[i].to]=dis[x]+c[i].cost;
				pre[c[i].to]=x;
				path[c[i].to]=i;
				if(vis[c[i].to]==0){
					queue[++tail]=c[i].to;
					vis[c[i].to]=1;
				}
			}
		}
	}
	if(pre[t]==-1) {
		return false;
	} else {
		return true;
	}
}
int dinic(int s,int t) {
	int f=0x7ffffff,ans=0;
	while(bfs(s,t)) {
		for(int i=t; i!=s; i=pre[i]) {
			if(c[path[i]].vv<f) {
				f=c[path[i]].vv;
			}
		}
		ans+=dis[t]*f;
		for(int i=t; i!=s; i=pre[i]) {
			c[path[i]].vv-=f;
			c[path[i]^1].vv+=f;
		}
	}
	return ans;
}
int main(){
	freopen("napkin.in","r",stdin);
	freopen("napkin.out","w",stdout);
	memset(r,-1,sizeof(r));
	t=read();
	for(int i=1; i<=t; i++) {
		day[i]=read();
	}
	p=read();
	m=read();
	f=read();
	n=read();
	s=read();
	build();
	int ans=dinic(S,T);
	printf("%d\n",ans);
	return 0;
}

 

     

posted @ 2017-07-31 17:27  Forever_goodboy  阅读(194)  评论(0编辑  收藏  举报