[网络流24题]餐巾计划问题

题目:洛谷P1251。

题目大意:
一个餐厅N天,每天需要ri块餐巾。每块餐巾需要p元,每天用过的餐巾变脏,不能直接用。现在有快洗店和慢洗店,快洗店洗餐巾需要m天,每块花费f元;慢洗店洗餐巾需要n天,每块餐巾s元(m < n,s<  f)。现要求最新的花费使满足每天所需。
解题思路:
最小费用最大流建模。
把每天拆成白天和晚上(白天产生脏餐巾,晚上得到干净餐巾)。
从S向每个白天连容量ri,费用0的边;从每个晚上向T连容量ri,费用0的边。代表每天所需的餐巾数。
从第i天的白天向第i+m天的晚上连容量无穷,费用f的边。(快洗)
从第i天的白天向第i+n天的晚上连容量无穷,费用s的边。(慢洗)
从S向每天晚上连容量无穷,费用p的边,代表直接买干净的餐巾。
从第i天晚上向第i+1天晚上连容量无穷,费用0的边,代表干净餐巾可以留到下一天。
跑费用流即可。

C++ Code:

#include<bits/stdc++.h>
using namespace std;
#define T 7000
#define N 7005
#define LoveLive long long
#define inf 0x3f3f3f3f
int n,p,m,f,nn,s,h[2005];
inline int readint(){
	int c=getchar(),d=0;
	for(;!isdigit(c);c=getchar());
	for(;isdigit(c);c=getchar())
	d=(d<<3)+(d<<1)+(c^'0');
	return d;
}
struct Graph{
	std::queue<int>q;
	int head[N],cnt,pre_e[N],a[N];
	LoveLive d[N];
	bool vis[N];
	struct edge{
		int from,to,cap,cost,nxt;
	}e[1000005];
	inline void addedge(const int u,const int v,const int flow,const int cost){
		e[++cnt]=(edge){u,v,flow,cost,head[u]};
		head[u]=cnt;
		e[++cnt]=(edge){v,u,0,-cost,head[v]};
		head[v]=cnt;
	}
	Graph():cnt(1){
		memset(head,-1,sizeof head);
	}
	bool bfs(LoveLive& flow,LoveLive& cost){
		memset(d,0x3f,sizeof d);
		memset(a,0x3f,sizeof a);
		memset(vis,0,sizeof vis);
		memset(pre_e,0,sizeof pre_e);
		d[0]=0;
		vis[0]=1;
		q.push(0);
		while(!q.empty()){
			int u=q.front();q.pop();
			vis[u]=0;
			for(int i=head[u];~i;i=e[i].nxt)
			if(e[i].cap&&d[e[i].to]>d[u]+e[i].cost){
				d[e[i].to]=d[u]+e[i].cost;
				a[e[i].to]=min(a[u],e[i].cap);
				pre_e[e[i].to]=i;
				if(!vis[e[i].to]){
					vis[e[i].to]=1;
					q.push(e[i].to);
				}
			}
		}
		if(d[T]>100000000000000000)return 0;
		flow+=a[T];
		cost+=d[T]*a[T];
		for(int i=T;i;i=e[pre_e[i]].from){
			e[pre_e[i]].cap-=a[T];
			e[pre_e[i]^1].cap+=a[T];
		}
		return 1;
	}
	LoveLive ek(){
		LoveLive flow=0,cost=0;
		while(bfs(flow,cost));
		return cost;
	}
}g;
int main(){
	n=readint();
	for(int i=1;i<=n;++i)h[i]=readint();
	p=readint(),m=readint(),f=readint(),nn=readint(),s=readint();
	for(int i=1;i<=n;++i){
		g.addedge(0,i,h[i],0);
		g.addedge(i+n,T,h[i],0);
		if(i+m<=n)g.addedge(i,i+n+m,inf,f);
		if(i+nn<=n)g.addedge(i,i+n+nn,inf,s);
		g.addedge(0,i+n,inf,p);
		if(i!=n)g.addedge(i,i+1,inf,0);
	}
	cout<<g.ek()<<endl;
	return 0;
}
原文地址:https://www.cnblogs.com/Mrsrz/p/9130400.html