[HNOI2001] 软件开发

· · 个人记录

题面:

某软件公司正在规划一项n天的软件开发计划,根据开发计划第i天需要ni个软件开发人员,为了提高软件开发人员的效率,公司给软件人员提供了很多的服务,其中一项服务就是要为每个开发人员每天提供一块消毒毛巾,这种消毒毛巾使用一天后必须再做消毒处理后才能使用。消毒方式有两种,A种方式的消毒需要a天时间,B种方式的消毒需要b天(b>a),A种消毒方式的费用为每块毛巾fA, B种消毒方式的费用为每块毛巾fB,而买一块新毛巾的费用为f(新毛巾是已消毒的,当天可以使用);而且f>fA>fB。公司经理正在规划在这n天中,每天买多少块新毛巾、每天送多少块毛巾进行A种消毒和每天送多少块毛巾进行B种消毒。当然,公司经理希望费用最低。你的任务就是:为该软件公司计划每天买多少块毛巾、每天多少块毛巾进行A种消毒和多少毛巾进行B种消毒,使公司在这项n天的软件开发中,提供毛巾服务的总费用最低。

思路:

这题的建图还是十分困难的

首先对于一个点我们肯定是要拆成两个点的

然后对于买的毛巾与洗后的毛巾应该处于统一层

所以s(源)向每个(i+n)连(f,inf)的边

每个(i)向(i+a+n+1)连(fa, inf)的边

每个(i)向(i+b+n+1)连(fb, inf)的边

由于一天没用的毛巾可以留到下一天所以对于

每个(i)向(i+1)连(0,inf)的边

最后

每个(s)向(i)连(0,di[i])的边

每个(i+n)向(t)连(0,di[i])的边

建图完成

代码:

#include<cstdio>
#include<cstring>
#define REP(i,a,b) for(register int i = a; i <= b; ++i)

const int MAXN = 2e3 + 50;
const int inf = 0x3f3f3f3f;

inline int min(int a, int b) {return a > b ? b : a;}
inline int max(int a, int b) {return a > b ? a : b;}

inline int read() {
    int x = 0 , f = 1; char c; while((c = getchar()) > '9' || c < '0') if(c == '-') f = 0; x = c - 48;
    while((c = getchar()) >= '0' && c <= '9') x = (x << 1) + (x << 3) + c - 48; return f ? x : ~x + 1;
}

int s, t, n, a, b, ff, fa, fb, ans = 0, ni[MAXN];
int Head[MAXN], cnt = 0;
struct edge {int to, nxt, cap, dis;} E[50005];
inline void add(int u, int v, int c, int f) {
    E[cnt] = edge {v, Head[u], c,  f}; Head[u] = cnt ++;
    E[cnt] = edge {u, Head[v], 0, -f}; Head[v] = cnt ++;
}

int Q[1000005], d[MAXN], pre[MAXN], cur[MAXN], l = 1, r = 0; bool inq[MAXN]; 
inline bool spfa() {    
    REP(i,0,t) d[i] = inf, pre[i] = 0, cur[i] = 0, inq[i] = false;
    d[Q[++r]=s] = 0;
    while(l <= r) {
        int u = Q[l++]; inq[u] = false;
        for(register int i = Head[u]; ~i; i = E[i].nxt) {
            int v = E[i].to; if(E[i].cap<=0||d[v]<=d[u]+E[i].dis) continue;
            d[v]=d[u]+E[i].dis; pre[v] = u; cur[v] = i; 
            if(inq[v]) continue; inq[v] = true;
            if(l&&d[Q[l]]>=d[v]) Q[--l] = v; else Q[++r] = v;
        }
    }
    return d[t] < inf;
}

inline int Augment() {
    int u = t, low = inf, res = 0;
    while(u != s) low = min(low, E[cur[u]].cap), u = pre[u]; u = t;
    while(u != s) E[cur[u]].cap -= low, E[cur[u]^1].cap += low, res += E[cur[u]].dis*low, u = pre[u];
    return res;
}

int main() {
    memset(Head, -1, sizeof(Head));
    n = read(); a = read(); b = read();
    ff= read(); fa= read(); fb= read();
    REP(i,1,n) ni[i] = read();
    s = 0; t = n*2+1;
    REP(i,1,n) add(s, i, ni[i], 0);
    REP(i,1,n-1) add(i, i+1, inf, 0); 
    REP(i,1,n) add(i+n, t, ni[i], 0);
    REP(i,1,n) add(s, i+n, inf, ff);
    for(register int i = 1; i+a+1 <= n; ++i)
    add(i, i+a+n+1, inf, fa);
    for(register int i = 1; i+b+1 <= n; ++i)
    add(i, i+b+n+1, inf, fb);
    while(spfa()) ans += Augment();
    printf("%d\n", ans);
    return 0;
}