题目描述
一个餐厅在相继的 NN 天里,每天需用的餐巾数不尽相同。假设第 ii 天需要 r_iri块餐巾( i=1,2,...,N)。餐厅可以购买新的餐巾,每块餐巾的费用为 pp 分;或者把旧餐巾送到快洗部,洗一块需 m 天,其费用为 f 分;或者送到慢洗部,洗一块需 nn 天(n>mn>m),其费用为 ss 分(s<fs<f)。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
试设计一个算法为餐厅合理地安排好 NN 天中餐巾使用计划,使总的花费最小。编程找出一个最佳餐巾使用计划。
输入格式
由标准输入提供输入数据。文件第 1 行有 1 个正整数 NN,代表要安排餐巾使用计划的天数。
接下来的 NN 行是餐厅在相继的 NN 天里,每天需用的餐巾数。
最后一行包含5个正整数p,m,f,n,sp,m,f,n,s。pp 是每块新餐巾的费用; mm 是快洗部洗一块餐巾需用天数; ff 是快洗部洗一块餐巾需要的费用; nn 是慢洗部洗一块餐巾需用天数; ss 是慢洗部洗一块餐巾需要的费用。
输出格式
将餐厅在相继的 N 天里使用餐巾的最小总花费输出
输入输出样例
输入 #1复制
3 1 7 5 11 2 2 3 1
输出 #1复制
134
说明/提示
N<=2000
ri<=10000000
p,f,s<=10000
时限4s
一道建图特别清新的一道题
注意要开long long
#include<bits/stdc++.h>
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
long long head[maxn];
long long vis[maxn];
long long dis[maxn];
long long flow[maxn];
long long pre[maxn];
long long last[maxn];
long long tot;
long long n, m, s, t;
using namespace std;
struct node{
long long to;
long long next;
long long f;
long long w;
node() {}
node(long long a, long long b, long long c, long long d) : to(a), next(b), f(c), w(d) {}
}edge[maxn * 10];
void edgeadd(long long a, long long b, long long c, long long d){
edge[tot] = node(b, head[a], c, d);
head[a] = tot++;
edge[tot] = node(a, head[b], 0, -d);
head[b] = tot++;
}
void init(){
memset(head, -1, sizeof(head));
tot = 0;
}
void spfainit(){
memset(vis, 0, sizeof(vis));
memset(dis, 0X3f3f3f3f, sizeof(dis));
memset(flow, 0x3f3f3f3f, sizeof(flow));
}
bool spfa(){
spfainit();
queue<long long> q;
q.push(s);
pre[t] = -1;
vis[s] = 1;
dis[s] = 0;
//flow[s] = 0;
while(!q.empty()){
long long nw = q.front();
q.pop();
vis[nw] = 0;
for(long long i = head[nw]; i != -1; i = edge[i].next){
long long y = edge[i].to;
long long w = edge[i].w;
long long f = edge[i].f;
if(f && dis[y] > dis[nw] + w){
dis[y] = dis[nw] + w;
flow[y] = min(flow[nw], f);
pre[y] = nw;
last[y] = i;
if(!vis[y]){
q.push(y);
vis[y] = 1;
}
}
}
}
return pre[t] != -1;
}
void dinic(){
long long maxflow = 0, minw = 0;
while(spfa()){
maxflow += flow[t];
minw += flow[t] * dis[t];
long long x = t;
while(x != s){
edge[last[x]].f -= flow[t];
edge[(last[x] ^ 1)].f += flow[t];
x = pre[x];
}
}
cout << minw << endl;
}
int main(){
ios::sync_with_stdio(false);
cin >> n;
init();
s = 0;
t = 2 * n + 1;
for(long long i = 1; i <= n; i++){
cin >> m;
edgeadd(s, i, m, 0);
edgeadd(i + n, t, m, 0);
}
long long a, b, c, d, e;
cin >> a >> b >> c >> d >> e;
for(long long i = 1; i <= n; i++){
edgeadd(0, i + n, inf, a);
if(i + 1 <= n) edgeadd(i, i + 1, inf, 0);
if(i + b <= n) edgeadd(i, i + n + b, inf, c);
if(i + d <= n) edgeadd(i, i + n + d, inf, e);
}
dinic();
return 0;
}