POJ1275 Cashier Employment 【二分 + 差分约束】

题目链接

POJ1275

题解

显然可以差分约束
我们记\(W[i]\)\(i\)时刻可以开始工作的人数
\(s[i]\)为前\(i\)个时刻开始工作的人数的前缀和

每个时刻的要求\(r[i]\),可以通过如下限制满足:
\[s[i] - s[i - 8] \ge r[i]\]
\[0 \le s[i] - s[i - 1] \le W[i]\]

但是\(i - 8\)可能为负,回到上一天的时刻,导致区间不连续,不好处理
我们可以二分答案\(sum\)
\(i < 8\)的部分改为:
\[s[i + 16] - s[i] \le sum - R[i]\]
再加一个
\[s[24] - s[0] \ge sum\]
这样就可以了

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 105,maxm = 1000005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out * flag;
}
int h[maxn],ne;
struct EDGE{int to,nxt,w;}ed[maxm];
inline void build(int u,int v,int w){
    ed[++ne] = (EDGE){v,h[u],w}; h[u] = ne;
}
int n,R[50],W[50];
int d[maxn],vis[maxn],cnt[maxn];
int q[maxm],head,tail;
bool spfa(){
    for (int i = 0; i <= 24; i++) d[i] = -INF,vis[i] = false,cnt[i] = 0;
    d[0] = 0; q[head = tail = 0] = 0;
    int u;
    while (head <= tail){
        u = q[head++];
        vis[u] = false; cnt[u]++;
        if (cnt[u] >= 25) return false;
        Redge(u) if (d[to = ed[k].to] < d[u] + ed[k].w){
            d[to] = d[u] + ed[k].w;
            if (!vis[to]) vis[to] = true,q[++tail] = to;
        }
    }
    return true;
}
bool check(int sum){
    for (int i = 1; i <= 24; i++) if (R[i] > sum) return false;
    cls(h); ne = 0;
    for (int i = 1; i < 8; i++) build(i + 16,i,R[i] - sum);
    for (int i = 8; i <= 24; i++) build(i - 8,i,R[i]);
    for (int i = 1; i <= 24; i++){
        build(i - 1,i,0);
        build(i,i - 1,-W[i]);
    }
    build(0,24,sum);
    return spfa();
}
int main(){
    int T = read();
    while (T--){
        for (int i = 1; i <= 24; i++)
            R[i] = read(),W[i] = 0;
        n = read(); int x;
        REP(i,n){
            x = read() + 1;
            W[x]++;
        }
        int l = 0,r = n,mid,flag = false;
        while (l < r){
            mid = l + r >> 1;
            if (check(mid)) r = mid,flag = true;
            else l = mid + 1;
        }
        if (!flag) puts("No Solution");
        else printf("%d\n",l);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Mychael/p/9160641.html