HDU1529 Cashier Employment(差分约束+二分答案)

题意:有家24小时营业的超市,现在给出每个小时需要的员工数Ri(i = 0, 1, 2, ..., 23),Ri表示从时刻i开始的一个小时内需要的员工数。现在有N名员工可以上岗,每人都有一个固定的上岗时间,且每个人只会在上岗之后固定工作八个小时,不会换班。求在满足人数要求的前提下,可以安排的最少员工数。可能无解。

思路:真是一个思维好题。

设ai为第i小时实际上岗的人数,Si为前i小时一共上岗的人数,则有 ai = Si - Si-1,ai未知。

设bi为第i小时需要的人数,则bi已知。

设ci为第i小时能够上岗的最大人数,则ci已知。

显然,可以得到下列不等式:

0 <= Si - Si-1 <= ci ,(i = 0, 1,2,...,23)

S(i) - S(i-8) >= bi, (i >= 7)

Si + S23 - S(i + 16)  >= bi, (i < 7)

有了上面的不等式组,很显然我们只需要求出 S(23) - S(-1) 的最小值就是答案,方便起见将所有下标向右移一位,得到新的不等式组:

0 <= S(i) - S(i-1) <= ci, (S0 = 0, i = 1, 2, 3,..., 24)                     (1)

S(i) - S(i - 8) >= bi, (i >= 8)                                                        (2)

Si + S24 - S(i + 16) >= bi, (i < 8)                                               (3)

对(3)式移项,得

Si - S(i + 16) >= bi - S24, (i < 8)                                                (4)

其中(1)式和(2)可以直接在图中建立相应的边,但是(4)式中存在一个未知的常量S24,而24显然就是我们的答案。想到二分答案的方法,将答案记为X,则有

Si - S(i + 16) >= bi - X, (i < 8)                                                  (5)

此时还需要添加一个限制条件,即 S24 - S0 == X,可表示为下面的形式加入到差分约束系统中。

S24 - X >= S0                                                                            (6)

S24 - X <= S0                                                                            (7)

好了,到这里这道题目的建图过程完成了,要求的是最小的解,跑最长路即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <cstdlib>
#include <set>
#include <string>

using namespace std;

typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 105;
struct edg{
    int v, d, nxt;
}G[maxn];
int pre[maxn], tot, dis[maxn], times[maxn];
bool vis[maxn];
int b[25], c[25];
void add(int u, int v, int w) {
    G[tot].v = v;
    G[tot].d = w;
    G[tot].nxt = pre[u];
    pre[u] = tot++;
}
int spfa(int x) {
    memset(times, 0, sizeof(times));
    memset(vis, 0, sizeof(vis));
    for (int i = 0; i < 24; ++i) {
        dis[i] = -inf; // 求最长路,初始化成负无穷
    }
    queue<int> que;
    dis[0] = 0;
    vis[0] = true;
    que.push(0);
    while (!que.empty()) {
        int u = que.front();
        que.pop();
        vis[u] = false;
        for (int i = pre[u]; ~i; i = G[i].nxt) {
            int v = G[i].v, w = G[i].d;
            if (dis[u] + w > dis[v]) {
                dis[v] = dis[u] + w;
                if (!vis[v]) {
                    vis[v] = true;
                    if (++times[v] > 25) {
                        return false;
                    }
                    que.push(v);
                }
            }
        }
    }
    return true;
}
bool jud(int x) {
    tot = 0;
    memset(pre, -1, sizeof(pre));
    for (int i = 1; i <= 24; ++i) {
        add(i, i - 1, -c[i]);               //S(i) - S(i-1) <= ci
        add(i - 1, i, 0);                   //0 <= S(i) - S(i-1)
        if (i >= 8) {
            add(i - 8, i, b[i]);            //S(i) - S(i - 8) >= bi
        } else {
            add(i + 16, i, b[i] - x);       //Si - S(i + 16) >= bi - X
        }
    }
    add(0, 24, x);                          //S24 - X >= S0
    add(24, 0, -x);                         //S24 - X <= S0
    return spfa(x);
}
int main() {
    int t, x, n;
    scanf("%d", &t);
    while (t--) {
        for (int i = 1; i <= 24; ++i) {
            scanf("%d", &b[i]);
        }
        memset(c, 0, sizeof(c));
        scanf("%d", &n);
        for (int i = 0; i < n; ++i) {
            scanf("%d", &x);
            ++c[x + 1];
        }
        int l = 0, r = n, f = 0;
        while (r - l > 1) {
            int mid = (r + l) >> 1;
            if (jud(mid)) {
                f = 1;
                r = mid;
            } else {
                l = mid;
            }
        }
        if (f) {
            printf("%d\n", r);
        } else {
            puts("No Solution");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hcx11333/article/details/81396704