• POJ1275 Cashier Employment 差分约束(优化 二分)


    题面

    一家超市要每天24小时营业,为了满足营业需求,需要雇佣一大批收银员。

    已知不同时间段需要的收银员数量不同,为了能够雇佣尽可能少的人员,从而减少成本,这家超市的经理请你来帮忙出谋划策。

    经理为你提供了一个各个时间段收银员最小需求数量的清单R(0),R(1),R(2),…,R(23)。

    R(0)表示午夜00:00到凌晨01:00的最小需求数量,R(1)表示凌晨01:00到凌晨02:00的最小需求数量,以此类推。

    一共有N个合格的申请人申请岗位,第 i 个申请人可以从ti时刻开始连续工作8小时。

    收银员之间不存在替换,一定会完整地工作8小时,收银台的数量一定足够。

    现在给定你收银员的需求清单,请你计算最少需要雇佣多少名收银员。

    输入格式

    第一行包含一个不超过20的整数,表示测试数据的组数。

    对于每组测试数据,第一行包含24个整数,分别表示R(0),R(1),R(2),…,R(23)。

    第二行包含整数N。

    接下来N行,每行包含一个整数ti。

    输出格式

    每组数据输出一个结果,每个结果占一行。

    如果没有满足需求的安排,输出“No Solution”。

    数据范围

    0≤R(0)≤1000,
    0≤N≤1000,
    0≤ti≤23
    

    输入样例:

    1
    1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
    5
    0
    23
    22
    1
    10
    

    输出样例:

    1
    

    题解

    看题目, 又是一堆不等式约束, 就想差分约束

    老套路 设s[i] 表示 [0, i] 时间段内正在工作和已经工作完的总人数,

    考虑到, 差分约束, 要从个入点开始, 也就是-1,

    所以我们右移, 将 0~23 小时变为 1~24 小时, 0为入点且s[0] ≡ 0;

    然而这是个环, 我们要拆环, 如果从 昨天工作到今天凌晨的不算入 s[1],

    所以对 每小时的工作人数, 可这样获得(每个人工作8小时)

    i >= 8, s[i] - s[i- 8] >= R[i - 1] ps:时间被我们右移了
    i <= 7, s[i] + s[24] - s[24 - 8 + i] >= R[i - 1]
    

    我们要将所有节点(小时)连接起来, 设b[i], 表示 在第i小时(平移过的)有多少人可以开始工作

    s[i] - s[i - 1] >= 0
    s[i] - s[i - 1] <= b[i]
    s[24] - s[0] <= n
    s[24] - s[0] >= 0
    

    整理得

    s[0] = 0
    s[i] >= s[i- 1]
    s[i - 1] >= s[i] - b[i]
    i >= 8, s[i] >= s[i - 8] + R[i - 1]
    i <= 7, s[i] >= s[16 + i] - s[24] + R[i - 1]
    s[0] >= s[24] - n
    s[24] >= s[0] 
    

    问题来了, (1)对于 i<= 7 的不等式, 怎么和两个点有关

    再仔细一看, s[24]正是我们所求, 且s[24]是个与i无关的数, 即"常数"

    所以我们可以枚举 s[24] 为 s24, 然后使得 s[24] - s[0] <= s24, s[24] - s[0] >= s24, 强制约束

    由于求最小值, 从小到大枚举即可,

    思考的, s[24]是单调的, 那么就可以二分

    然后就是建边问题, 我们按照

    s[i] >= s[i- 1]
    s[i - 1] >= s[i] - b[i]
    i >= 8, s[i] >= s[i - 8] + R[i - 1]
    
    i <= 7, s[i] >= s[16 + i] -+ R[i - 1]
    s[0] >= s[24]
    s[24] >= s[0]
    

    对于 边的序号 > 65的边 在搜索时取花费时额外 减去当前枚举的 s24, 并且 左后一条边的花费预先 加上 s24 * 2(取的时候 -s24)

    #include <bits/stdc++.h>
    #define all(n) (n).begin(), (n).end()
    #define se second
    #define fi first
    #define pb push_back
    #define mp make_pair
    #define sqr(n) (n)*(n)
    #define rep(i,a,b) for(int i=(a);i<=(b);++i)
    #define per(i,a,b) for(int i=(a);i>=(b);--i)
    #define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> PII;
    typedef pair<ll, ll> PLL;
    typedef vector<int> VI;
    typedef double db;
    
    const int N = 25;
    
    int n, m, _, k;
    int h[N], ne[3 * N], to[3 * N], co[3 * N], tot;
    int a[N], b[N], dis[N], dep[N];
    bool v[N];
    
    void add(int u, int v, int c) {
        ne[++tot] = h[u]; to[h[u] = tot] = v; co[tot] = c;
    }
    
    bool sfpa(int mid) {
        stack<int> st; st.push(0);
        rep(i, 0, 24) v[i] = 0;
        co[tot] = (mid << 1);
        memset(dis, -0x3f, sizeof dis);
        dep[0] = dis[0] = 0;
        while (!st.empty()) {
            int x = st.top(); st.pop(); v[x] = 0;
            for (int i = h[x]; i; i = ne[i]) {
                int y = to[i], c = co[i] - (i > 65) * mid;
                if (dis[y] >= dis[x] + c) continue;
                dis[y] = dis[x] + c; dep[y] = dep[x] + 1;
                if (dep[y] >= 25) return 0;
                if (!v[y]) v[y] = 1, st.push(y);
            }
        }
        return 1;
    }
    
    int main() {
        IOS;
        for (cin >> _; _; --_) {
            h[0] = tot = 0;
            rep(i, 1, 24) h[i] = b[i] = 0, cin >> a[i];
            cin >> n;
            rep(i, 1, n) cin >> m, ++b[++m];
            rep(i, 1, 24) add(i, i - 1, -b[i]), add(i - 1, i, 0);
            rep(i, 8, 24) add(i - 8, i, a[i]);
            rep(i, 1, 7) add(i + 16, i, a[i]);
            add(24, 0, 0); add(0, 24, 0);
    
            int l = 0, r = n + 1;
            while (l < r) {
                int mid = (l + r) >> 1;
                if (sfpa(mid)) r = mid;
                else l = mid + 1;
            }
            if (r == n + 1) cout << "No Solution
    ";
            else cout << r << '
    ';
        }
        return 0;
    }
    
  • 相关阅读:
    AMR转换MP3 linuxCentOS 版(不管任何语言可以使用shell命令在linux执行转换语句)
    MySql 入门——日期计算
    javascript深度剖析之 【 var 关键字】。
    javascript动画浅析。
    javascript之this关键字浅析。
    javascript【AMD模块加载器】浅析V3(添加CSS加载功能,重构内部流程)
    html5 canvas 自制小游戏系列之 【贪吃蛇】。
    javascript设计模式简单介绍之【工厂模式】
    javascript【AMD模块加载器】浅析
    javascript【AMD模块加载器】浅析V2(整合DOM ready)
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/13620294.html
Copyright © 2020-2023  润新知