2375: 【网络流】餐巾计划问题
时间限制: 1 Sec 内存限制: 128 MB题目描述
一个餐厅在相继的N 天里,每天需用的餐巾数不尽相同。假设第i天需要ri块餐巾(i=1,2,…,N)。餐厅可以购买新的餐巾,每块餐巾的费用为p分;或者把旧餐巾送到快洗部,洗一块需m天,其费用为f 分;或者送到慢洗部,洗一块需n 天(n>m),其费用为s<f 分。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
试设计一个算法为餐厅合理地安排好N 天中餐巾使用计划,使总的花费最小。
输入
文件第1 行有6 个正整数N,p,m,f,n,s。N 是要安排餐巾
使用计划的天数;p 是每块新餐巾的费用;m 是快洗部洗一块餐巾需用天数;f 是快洗部洗
一块餐巾需要的费用;n是慢洗部洗一块餐巾需用天数;s是慢洗部洗一块餐巾需要的费用。
接下来的N 行是餐厅在相继的N 天里,每天需用的餐巾数。
输出
程序运行结束时,将餐厅在相继的N 天里使用餐巾的最小总花费输出到文件output.txt中。
样例输入
3 10 2 3 3 2
5
6
7
样例输出
145
建立一个二分图,X部Y部各N个点,
Xi表示第i天用掉的餐巾数,从Src连边至Xi边的容量为x(即题中给出的每天要用的数量),
Yi表示第i天之前至少要准备好的(即第i天需要用的)餐巾数,从Yi连边至Tar边的容量为x
对于Xi,
可以选择将Xi中的移至快洗部Xi -> Yi + m,容量无限,费用f,
可以移至慢洗部Xi -> Yi + n,容量无限,费用s,
还可以留下来到下一天Xi -> Xi + 1,容量无限,费用0
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
const int Max = 2005;
const int Maxm = 100005;
const int INF = 0x3f3f3f3f;
struct node{
int v, cap, cost, nxt;
}edge[Maxm << 2];
int N, p, m, f, n, s;
int cnt = 1, Src, Tar, Flow, Cost;
int fir[Max], Dis[Max];
bool vis[Max], Inq[Max];
void getint(int & num){
char c; int flg = 1; num = 0;
while((c = getchar()) < '0' || c > '9') if(c == '-') flg = -1;
while(c >= '0' && c <= '9'){ num = num * 10 + c - 48; c = getchar();}
num *= flg;
}
void addedge(int a, int b, int c, int d){
edge[++ cnt].v = b, edge[cnt].cap = c, edge[cnt].cost = d, edge[cnt].nxt = fir[a], fir[a] = cnt;
edge[++ cnt].v = a, edge[cnt].cap = 0, edge[cnt].cost = -d, edge[cnt].nxt = fir[b], fir[b] = cnt;
}
int Aug(int i, int augco){
if(i == Tar){
Cost += Dis[Tar] * augco;
return augco;
}
int augc = augco, delta;
for(int j = fir[i]; j && augc; j = edge[j].nxt) if(edge[j].cap && ! vis[edge[j].v])
if(Dis[i] == Dis[edge[j].v] - edge[j].cost){
vis[edge[j].v] = 1;
delta = Aug(edge[j].v, min(augc, edge[j].cap));
edge[j].cap -= delta;
edge[j ^ 1].cap += delta;
augc -= delta;
}
return augco - augc;
}
queue<int>Q;
bool SPFA(){
memset(Dis, 0x3f, sizeof(Dis));
memset(Inq, 0, sizeof(Inq));
Dis[Src] = 0;
Q.push(Src);
while(! Q.empty()){
int tmp = Q.front(); Q.pop();
Inq[tmp] = 0;
for(int j = fir[tmp]; j; j = edge[j].nxt)
if(edge[j].cap && Dis[edge[j].v] > Dis[tmp] + edge[j].cost){
Dis[edge[j].v] = Dis[tmp] + edge[j].cost;
if(! Inq[edge[j].v]) Inq[edge[j].v] = 1, Q.push(edge[j].v);
}
}
return Dis[Tar] != Dis[Tar + 1];
}
int MCMF(){
Flow = 0, Cost = 0;
while(SPFA()){
memset(vis, 0, sizeof(vis));
vis[Src] = 1;
Flow += Aug(Src, INF);
}
return Cost;
}
int main(){
getint(N), getint(p), getint(m), getint(f), getint(n), getint(s);
Src = 0, Tar = N << 1| 1;
int x;
for(int i = 1; i <= N; ++ i){
getint(x);
addedge(Src, i, x, 0);
addedge(i + N, Tar, x, 0);
addedge(Src, i + N, INF, p);
if(i + m <= N) addedge(i, i + m + N, INF, f);
if(i + n <= N) addedge(i, i + n + N, INF, s);
if(i < N) addedge(i, i + 1, INF, 0);
}
printf("%d\n", MCMF());
return 0;
}