Acwing393. 雇佣收银员 题解 差分约束

题目链接:https://www.acwing.com/problem/content/description/395/

解题思路:

差分约束。

为了方便起见,定义第 \(i\) 个时间段为 \(i-1:00\)\(i:00\) 这个时间段。

首先,为了方便开一个额外的点,令 \(R_i\) 对应为题目中的 \(R(i+1)\),即 \(R_i\) 表示 \(i-1:00\)\(i:00\) 这个时间段的最小需求人数。即用 \(R_i\) 替代 \(R(i+1)\) 表示第 \(i\) 个时间段人数的需求量。

然后,统计一下每个时间段能够供给的最大人数,用 \(num_i\) 表示第 \(i\) 个时间段能够供给的最大人数。

\(x_i\) 表示第 \(i\) 个时间段需要分配的最小人数,可以得到以下式子:

  • \(0 \le x_i \le num_i\),①
  • \(x_{i-7} + x_{i-6} + \cdots + x_i \ge r_i\),②

上述这个式子不具有差分约束的一般性,所以开一个前缀和,定义 \(S_i = \sum\limits_{j=1}^i x_j\),上述不等式组转换为:

  • \(0 \le S_i - S_{i-1} \le num_i\),对任意 \(1 \le i \le 24\)
  • \(8 \le i \le 24\) 时,有
    • \(S_i - S_{i-8} \ge r_i\)
  • \(1 \le i \le 7\) 时,有
    • \(S_i + S_{24} - S_{i+16} \ge r_i\)

将上面这些式子重新梳理一下得:

  1. 对于任意 \(1 \le i \le 24\),有 \(S_i \ge S_{i-1} + 0\)
  2. 对于任意 \(1 \le i \le 24\),有 \(S_{i-1} \ge S_i - num_i\)
  3. 对于任意 \(8 \le i \le 24\),有 \(S_i \ge S_{i-8} + r_i\)
  4. 对于任意 \(1 \le i \le 7\),有 \(S_i \ge S_{i+16} + r_i - S_{24}\)

显然第 \(4\) 种情况还是不具有差分约束的一般性。

但是可以发现 \(S_{24} \le N \le 1000\),所以可以从 \(0\)\(N\)枚举 \(S_{24}\) 的值,差分约束建图判断是否存在负环。不存在负环的最小的 \(S_{24}\) 就是我们所需的答案。

另外,因为 \(S_{24}\) 目前是一个固定值,所以我们还可以得到一个等式:

\(S_{24} = S_0 + C\)

其中 \(C\) 对应的就是 \(S_{24}\) 的固定的值。

所以,还需满足如下两个式子:

  • \(S_{24} \ge S_0 + C\)
  • \(S_0 \ge S_{24} - C\)

对应需要额外加两条边。

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 25;
struct Edge {
    int v, w;
};
vector<Edge> g[maxn];

int dis[maxn], cnt[maxn];
bool ins[maxn];
bool spfa() {
    stack<int> stk;
    memset(cnt, 0, sizeof(cnt));
    memset(ins, 0, sizeof(ins));
    memset(dis, -0x3f, sizeof(dis));
    dis[0] = 0;
    stk.push(0);
    while (!stk.empty()) {
        int u = stk.top();
        stk.pop();
        ins[u] = false;
        if (++cnt[u] >= 25)
            return false;
        for (auto e : g[u]) {
            int v = e.v, w = e.w;
            if (dis[v] < dis[u] + w) {
                dis[v] = dis[u] + w;
                if (!ins[v])
                    ins[v] = true, stk.push(v);
            }
        }
    }
    return true;
}

int T, r[maxn], N, num[maxn];

int cal() {
    for (int S24 = 0; S24 <= N; S24++) {
        for (int i = 0; i < 25; i++) g[i].clear();
        for (int i = 1; i <= 24; i++) {
            g[i-1].push_back({i, 0});
            g[i].push_back({i-1, -num[i]});
            if (i >= 8)
                g[i-8].push_back({i, r[i]});
            else
                g[i+16].push_back({i, r[i] - S24});
        }
        g[0].push_back({24, S24});
        g[24].push_back({0, -S24});
        if (spfa())
            return S24;
    }
    return -1;
}

int main() {
    scanf("%d", &T);
    while (T--) {
        for (int i = 1; i <= 24; i++)
            scanf("%d", r + i);
        memset(num, 0, sizeof(num));
        scanf("%d", &N);
        for (int i = 0; i < N; i++) {
            int t;
            scanf("%d", &t);
            t++;
            num[t]++;
        }
        int ans = cal();
        if (ans == -1)
            puts("No Solution");
        else
            printf("%d\n", ans);
    }
    return 0;
}
posted @ 2023-09-20 11:46  quanjun  阅读(5)  评论(0编辑  收藏  举报