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;
}