差分约束 : 雇佣收营员

雇佣收银员

分析

\(本题令s_i为0\sim i点需要的人数和\)

\(\color{Red}{s_i作为图中的点}\)

\(为了方便使用前缀和,r_i统一往后错一位,于是r_i表示i-1\sim i中需要的人数\)

\(因为24小时是一个环的形式,这里的前缀需要注意:\)

  • \(0\sim7小时间值班的人数:s_i+s_{24}-s_{i+16}\)
  • \(8\sim 24小时值班的人数:s_i-s_{i-8}\)
约束关系
  • \(s_i\ge s_{i-1}\)
  • \(s_{i-1}\ge s_i-num[i]\ 表示i-1\sim i最多只能招聘num[i]人.\)
  • \(i\le7 : s_i\ge s_{i+16}-s_{24}+r_i\)
  • \(i\ge 8:s_i\ge s_{i-8}+r_i\)
    \(条件3有3个未知数,所有去枚举s_{24}.\)
代码
#include <bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
inline int lowbit(int x) { return x & (-x); }
#define ll long long
#define pb push_back
#define PII pair<int, int>
#define x first
#define y second
#define inf 0x3f3f3f3f
const int N = 30, M = 100;
int n;
int h[N], e[M], w[M], ne[M], idx;
int r[N], num[N];
int dist[N];
int q[N], cnt[N];
bool st[N];

void add(int a, int b, int c) {
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}

void build(int c) { //c为s24, 枚举
    memset(h, -1, sizeof h);
    idx = 0;
    add(0, 24, c), add(24, 0, -c); //s24 <= c s24 >= c;
    for (int i = 1; i <= 7; ++i) add(i + 16, i, r[i] - c);
    for (int i = 8; i <= 24; ++i) add(i - 8, i, r[i]);
    for (int i = 1; i <= 24; ++i) {
        add(i, i - 1, -num[i]);
        add(i - 1, i, 0);
    }
}

bool spfa(int c) {
    build(c);
    memset(dist, -0x3f, sizeof dist);
    memset(cnt, 0, sizeof cnt);
    memset(st, 0, sizeof st);
    int hh = 0, tt = 1;
    dist[0] = 0;
    q[0] = 0;
    st[0] = true;
    while (hh != tt) {
        int t = q[hh++];
        if (hh == N) hh = 0;
        st[t] = false;
        for (int i = h[t]; ~i; i = ne[i]) {
            int j = e[i];
            if (dist[j] < dist[t] + w[i]) {
                dist[j] = dist[t] + w[i];
                cnt[j] = cnt[t] + 1;
                if (cnt[j] >= 25) return false;
                if (!st[j]) {
                    q[tt++] = j;
                    if (tt == N) tt = 0;
                    st[j] = true;
                }
            }
        }
    }
    return true;
}

int main() {
    //IO;
    int _;
    cin >> _;
    while (_--) {
        for (int i = 1; i <= 24; ++i) cin >> r[i];
        cin >> n;
        memset(num, 0, sizeof num);
        for (int i = 0; i < n; ++i) {
            int t;
            cin >> t;
            num[t + 1]++;
        }
        bool f = 0;
        for (int i = 0; i <= 1000; ++i) 
            if (spfa(i)) {
                cout << i << '\n';
                f = 1;
                break;
            }
        if (!f) puts("No Solution");
    }
    return 0;
}

posted @ 2021-02-18 00:51  phr2000  阅读(37)  评论(0编辑  收藏  举报