[BZOJ1221]&&[HNOI2001] 软件开发

描述 Description

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

输入格式 InputFormat

第 1 行为 n,a,b,f,fA,fB. 第 2 行为 n1,n2,……,nn. (注:1≤f,fA,fB≤60,1≤n≤1000)

输出格式 OutputFormat

最少费用

样例输入 SampleInput

10 2 5 10 7 5
71 17 93 10 82 38 92 4 66 14

样例输出 SampleOutput

3947


BZOJ 1221


把每天分为二分图两个集合中的顶点 Xi,Yi,建立附加源 S 汇 T。二分图 X 集合中顶点 Xi 表示第 i 天用完的餐巾, Y 集合中每个点 Yi 则是第 i 天需要的餐巾.

1、从 S 向每个 Xi 连一条容量为 ri,费用为 0 的有向边。

2、从每个 Yi 向 T 连一条容量为 ri,费用为 0 的有向边。

3、从 S 向每个 Yi 连一条容量为无穷大,费用为 p 的有向边。

4、从每个 Xi 向 Xi+1(i+1<=N) 连一条容量为无穷大,费用为 0 的有向边。

5、从每个 Xi 向 Yi+m(i+m<=N) 连一条容量为无穷大,费用为 f 的有向边。

6、从每个 Xi 向 Yi+n(i+n<=N) 连一条容量为无穷大,费用为 s 的有向边。

求网络最小费用最大流,费用流值就是要求的最小总花费。

#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const int inf = 0x7fffffff / 27.11;
const int maxn = 2005;
const int maxm = 6 * maxn;
int i, j, t, n, m, l, r, k, z, y, x;
int cnt, num, a, b, f, fa, fb;
struct edge
{
    int to, fl, co, nx;
} e[maxm];
int head[maxn], dis[maxn], used[maxn], pre[maxn];
deque <int> q;
inline void ins(int u, int v, int f, int c)
{
    e[cnt] = (edge)
    {
        v, f, c, head[u]
    };
    head[u] = cnt++;
    e[cnt] = (edge)
    {
        u, 0, -c, head[v]
    };
    head[v] = cnt++;
}
inline bool spfa(int s, int t, int tim)
{
    int i, u, v, w;
    while (!q.empty()) q.pop_front();
    for (i = s; i <= t; i++) dis[i] = inf;
    dis[s] = 0; used[s] = tim; pre[s] = -1;
    q.push_back(s);
    while (!q.empty())
    {
        u = q.front(); q.pop_front(); used[u] = 0;
        for (i = head[u]; i != -1; i = e[i].nx)
        {
            v = e[i].to; w = e[i].co;
            if (dis[v] > dis[u] + w && e[i].fl > 0)
            {
                dis[v] = dis[u] + w;
                pre[v] = i;
                if (used[v] != tim)
                {
                    used[v] = tim;
                    if (!q.empty() && dis[v] < dis[q.front()]) q.push_front(v);
                    else q.push_back(v);
                }
            }
        }
    }
    return (dis[t] != inf);
}
inline void mcmf(int s, int t)
{
    int i, f, ans = 0;
    while (spfa(s, t, ++num))
    {
        // cout << " " << ans << endl;
        for (f = inf, i = pre[t]; i != -1; i = pre[e[i ^ 1].to]) f = min(f, e[i].fl);
        for (i = pre[t]; i != -1; i = pre[e[i ^ 1].to]) e[i].fl -= f, e[i ^ 1].fl += f;
        ans += f * dis[t];
    }
    printf("%d\n", ans);
}
int main()
{
    cnt = num = 0;
    memset(head, -1, sizeof(head));
    scanf("%d%d%d%d%d%d", &n, &a, &b, &f, &fa, &fb);
    for (i = 1; i <= n; i++)
    {
        scanf("%d", &x);
        ins(0, i, x, 0);
        ins(n + i, 2 * n + 1, x, 0);
        ins(0, n + i, inf, f);
    }
    for (i = 1; i < n; i++) ins(i, i + 1, inf, 0);
    for (i = 1; i + a + 1 <= n; i++) ins(i, n + i + a + 1, inf, fa);
    for (i = 1; i + b + 1 <= n; i++) ins(i, n + i + b + 1, inf, fb);
    mcmf(0, 2 * n + 1);
    return 0;
}