【线性规划与网络流24题 10】餐巾计划

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


【分析】

最大流最小费用

我们将每天视为一个点,考虑到每天有两种状态,取餐巾和用餐巾,我们将每天拆为两个点,i和i'。再建源点Sta,和汇点End。

建图方式如下:

1.源点到i,容量为需要的餐巾量,费用为0;

2.i'到汇点,容量为需要的餐巾量,费用为0;

3.源点到i',容量为INF,费用为p;

4.i到(i+m)',容量为INF,费用为f;

5.i到(i+n)',容量为INF,费用为s;

6.i到i+1,容量为INF,费用0;

1的意思是有这么多可以拿来洗。3的意思是买餐巾。

4,5的意思是拿去洗,而6的意思是干净的留给下一天。


【代码】

/****************************
    ID:Ciocio
	LANG:C++
	DATE:2013-12-23
	TASK:Network_flow 10
****************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>

using namespace std;

#define MAXN (1005*2)
#define INF 0x7FFFFFFF
#define p_b push_back

int N,p,m,f,n,s,Sta,End;
struct edge{
	int from,to,cap,flow,cost;
	edge(int a,int b,int c,int d,int f):from(a),to(b),cap(c),flow(d),cost(f){}
};
int Dis[MAXN],path[MAXN],fl[MAXN];
bool inqueue[MAXN];
vector <edge> edges;
vector <int> g[MAXN];

void _addedge(int from,int to,int cap,int cost)
{
	edges.p_b(edge(from,to,cap,0,cost));
	edges.p_b(edge(to,from,0,0,-cost));
	int m=edges.size();
	g[from].p_b(m-2);
	g[to].p_b(m-1);
}

void _read(int &x)
{
	char tt=getchar();
	while(tt<'0'||'9'<tt) tt=getchar();
	for(x=0;'0'<=tt&&tt<='9';x=(x<<3)+(x<<1)+tt-'0',tt=getchar());
}

void _init()
{_read(N);_read(p);_read(m);_read(f);_read(n);_read(s);}

queue <int> Q;
bool _tryflow(int &flow,int &cost)
{
	for(int i=Sta;i<=End;i++) Dis[i]=INF;
	memset(inqueue,0,sizeof(inqueue));
	Dis[Sta]=0;inqueue[Sta]=true;path[Sta]=0;fl[Sta]=INF;
	while(!Q.empty()) Q.pop();
	Q.push(Sta);
	while(!Q.empty())
	{
		int u=Q.front();Q.pop();inqueue[u]=false;
		int sz=g[u].size();
		for(int j=0;j<sz;j++)
		{
			edge &e=edges[g[u][j]];
			if(e.cap>e.flow&&Dis[e.to]>Dis[u]+e.cost)
			{
				Dis[e.to]=Dis[u]+e.cost;
				path[e.to]=g[u][j];
				fl[e.to]=min(fl[u],e.cap-e.flow);
				if(!inqueue[e.to])
				{
					inqueue[e.to]=true;
					Q.push(e.to);
				}
			}
		}
	}
	if(Dis[End]==INF) return false;
	flow+=fl[End];
	cost+=fl[End]*Dis[End];
	int x=End;
	while(x!=Sta)
	{
		edges[path[x]].flow+=fl[End];
		edges[path[x]^1].flow-=fl[End];
		x=edges[path[x]].from;
	}
	return true;
}

void _solve()
{
	Sta=0;End=N*2+1;
	int need;
	for(int i=1;i<=N;i++)
	{
		_read(need);
		_addedge(Sta,i,need,0);
		_addedge(i+N,End,need,0);
		_addedge(Sta,i+N,INF,p);
		if(i+m<=N) _addedge(i,i+N+m,INF,f);
		if(i+n<=N) _addedge(i,i+N+n,INF,s);
		if(i+1<=N) _addedge(i,i+1,INF,0);
	}
	int Maxflow,Mincost;
	Maxflow=Mincost=0;
	while(_tryflow(Maxflow,Mincost));
	cout<<Mincost<<endl;
}

int main()
{
	_init();
	_solve();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值