还是
上的题, 这道题实际上根据描述来建图还是不难的, 但是我费用流模板打得好像太suo了所以一直
, 最后还是贴的自己板子, 看来还是要把基础模板再总结一遍
。
首先由于每个点有两个信息, 干净餐巾和脏餐巾, 那么我们把每个点拆成两个
分别存储这两个信息。首先每天可以购买新餐巾, 那么就从
向每一个
连一条流量为
, 费用为新餐巾价格的边, 每天需要
条餐巾, 那么就从每个
向
连流量为
, 费用为
的边, 每天的干净餐巾用完后就变脏了, 那么就可以从
向每一个
连一条流量为
, 费用为
的边, 每天的脏餐巾可以留到第二天, 所以每个
可以向下一天的
连一条流量为
, 费用为
的边, 最后快洗和慢洗就从每天的
向洗完后那天的
连流量为
, 费用为快洗或慢洗价格的边, 这样这个图就建完了。
正确性证明:首先每个点一定是可以每天都购买新餐巾的, 那么满流这个条件一定可以满足, 所以我们直接在最大流的基础上求解最小费用就ok了。
题目链接
Codes
#include<bits/stdc++.h>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)
#define go(x, i) for(register int i = head[x]; i; i = nxt[i])
#define int long long
using namespace std;
const int maxn = 2000 + 10, maxm = 5e5 + 10;
int n, p, qv, qd, sv, sd, Day[maxn], S, T;
template<class T>inline bool chkmin(T &_, T __) {
return _ > __ ? _ = __, 1 : 0;
}
namespace Mincost_Maxflow {
int to[maxm], head[maxm], w[maxm], v[maxm], nxt[maxm], e = 1;
int dis[maxm], vis[maxm], Cost;
inline void add(int x, int y, int z, int val) {
to[++ e] = y;
nxt[e] = head[x];
head[x] = e;
w[e] = z;
v[e] = val;
if(z) add(y, x, 0, -val);
}
inline bool SPFA() {
queue<int> q;
For(i, 1, n * 2 + 2) vis[i] = 0, dis[i] = 1e18;
q.push(vis[S] = S), dis[S] = 0;
while(!q.empty()) {
int k = q.front(); q.pop();
go(k, i)
if(w[i] && chkmin(dis[to[i]], dis[k] + v[i]) && !vis[to[i]])
q.push(vis[to[i]] = to[i]);
vis[k] = false;
}
return dis[T] < 1e18;
}
inline int dfs(int x, int flow) {
if(x == T || !flow)
return vis[x] = flow;
int used = 0; vis[x] = true;
go(x, i)
if(dis[to[i]] == dis[x] + v[i] && !vis[to[i]]) {
int di = dfs(to[i], min(flow, w[i]));
w[i] -= di, w[i ^ 1] += di;
used += di, flow -= di; Cost += di * v[i];
if(!flow) break;
}
return used;
}
inline int Flow() {
int res = 0;
while(SPFA()) {
vis[T] = true;
while(vis[T]) {
For(i, 1, n * 2 + 2)
vis[i] = 0;
res += dfs(S, 1e18);
}
}
return res;
}
}
main() {
#ifndef ONLINE_JUDGE
freopen("1251.in", "r", stdin);
freopen("1251.out", "w", stdout);
#endif
scanf("%lld", &n);
For(i, 1, n) scanf("%lld", &Day[i]);
scanf("%lld%lld%lld%lld%lld", &p, &qd, &qv, &sd, &sv);
S = 1, T = (n << 1) + 2;
For(i, 1, n) {
Mincost_Maxflow::add(S, i << 1, 1e18, p);
Mincost_Maxflow::add(i << 1, T, Day[i], 0);
Mincost_Maxflow::add(S, i << 1 | 1, Day[i], 0);
if(i + 1 <= n) Mincost_Maxflow::add(i << 1 | 1, (i + 1) << 1 | 1, 1e18, 0);
if(i + qd <= n) Mincost_Maxflow::add(i << 1 | 1, (i + qd) << 1, 1e18, qv);
if(i + sd <= n) Mincost_Maxflow::add(i << 1 | 1, (i + sd) << 1, 1e18, sv);
}
Mincost_Maxflow::Flow();
printf("%lld\n", Mincost_Maxflow::Cost);
return 0;
}