POJ 1275 二分 + 差分约束系统

题意

传送门 POJ 1275 Cashier Employment

题解

不等式问题,考虑转化为差分约束系统。某个时刻 i i i 的工作人数为前 8 8 8 个小时内开始工作的人数和,将其转化为前缀和 S S S 的差分。设 n u m [ i ] num[i] num[i] 为工作开始时间为时刻 i i i 的人数。
{ S [ i ] ≥ S [ i − 1 ] S [ i ] − S [ i − 1 ] ≤ n u m [ i ] S [ i ] − S [ j ] ≥ { R [ i ] i > j R [ i ] − ( S [ 23 ] − S [ − 1 ] ) i < j , j = ( i − 8 + 24 ) m o d    24 \begin{cases} S[i]\geq S[i-1] \\ S[i]-S[i-1]\leq num[i]\\ S[i]-S[j]\geq \begin{cases}R[i] &i>j\\ R[i]-(S[23]-S[-1]) & i<j\\ \end{cases} ,j = (i-8+24)\mod 24\\ \end{cases} S[i]S[i1]S[i]S[i1]num[i]S[i]S[j]{ R[i]R[i](S[23]S[1])i>ji<j,j=(i8+24)mod24 第三类不等式 i < j i<j i<j 的情况不满足差分约束的形式,不等式右侧存在变量 S [ 23 ] − S [ − 1 ] S[23]-S[-1] S[23]S[1],它代表总工作人数。那么二分答案,在确定 S [ 23 ] − S [ − 1 ] S[23]-S[-1] S[23]S[1] 的情况下,不等式组就转化为差分约束系统。为方便处理,将索引向右平移一个单位。设当前二分值为 S [ 24 ] − S [ 0 ] = x S[24]-S[0]=x S[24]S[0]=x
{ S [ i − 1 ] − S [ i ] ≤ 0 S [ i ] − S [ i − 1 ] ≤ n u m [ i ] S [ j ] − S [ i ] ≤ { − R [ i ] i > j x − R [ i ] i < j , j = ( i − 1 − 8 + 24 ) m o d    24 + 1 S [ 24 ] − S [ 0 ] ≤ x S [ 0 ] − S [ 24 ] ≤ − x \begin{cases} S[i-1]-S[i]\leq 0\\ S[i]-S[i-1]\leq num[i]\\ S[j]-S[i]\leq \begin{cases}-R[i] &i>j\\ x-R[i] & i<j\\ \end{cases} ,j = (i-1-8+24)\mod 24+1\\ S[24]-S[0]\leq x\\ S[0]-S[24]\leq -x\\ \end{cases} S[i1]S[i]0S[i]S[i1]num[i]S[j]S[i]{ R[i]xR[i]i>ji<j,j=(i18+24)mod24+1S[24]S[0]xS[0]S[24]x
S P F A SPFA SPFA 判定负环即可。总时间复杂度 O ( T 2 log ⁡ N ) O(T^2\log N) O(T2logN)

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int maxt = 30, maxm = 3 * maxt + 2;
int T, R[maxt], N, num[maxt], ds[maxt], cnt[maxt];
int tot, head[maxt], to[maxm], cost[maxm], nxt[maxm];
bool in[maxt];

inline void add(int x, int y, int z)
{
    
    
    to[++tot] = y, cost[tot] = z, nxt[tot] = head[x], head[x] = tot;
}

bool SPFA()
{
    
    
    memset(ds, 0x3f, sizeof(ds));
    memset(cnt, 0, sizeof(cnt));
    memset(in, 0, sizeof(in));
    ds[0] = 0, in[0] = 1;
    queue<int> q;
    q.push(0);
    while (q.size())
    {
    
    
        int x = q.front();
        q.pop(), in[x] = 0;
        for (int i = head[x]; i; i = nxt[i])
        {
    
    
            int y = to[i], z = cost[i];
            if (ds[x] + z < ds[y])
            {
    
    
                ds[y] = ds[x] + z, cnt[y] = cnt[x] + 1;
                if (cnt[y] > 24)
                    return 0;
                if (!in[y])
                    q.push(y), in[y] = 1;
            }
        }
    }
    return 1;
}

bool judge(int x)
{
    
    
    memset(head, 0, sizeof(head));
    tot = 0;
    for (int i = 1; i <= 24; ++i)
        add(i - 1, i, num[i]), add(i, i - 1, 0);
    for (int i = 1, j; i <= 24; ++i)
    {
    
    
        j = (i - 1 + 16) % 24 + 1;
        add(i, j, i > j ? -R[i] : x - R[i]);
    }
    add(0, 24, x), add(24, 0, -x);
    return SPFA();
}

int main()
{
    
    
    scanf("%d", &T);
    while (T--)
    {
    
    
        for (int i = 1; i <= 24; ++i)
            scanf("%d", R + i);
        scanf("%d", &N);
        memset(num, 0, sizeof(num));
        for (int i = 1, t; i <= N; ++i)
            scanf("%d", &t), ++num[t + 1];
        int lb = -1, ub = N + 1;
        while (ub - lb > 1)
        {
    
    
            int mid = (lb + ub) >> 1;
            if (judge(mid))
                ub = mid;
            else
                lb = mid;
        }
        if (ub > N)
            puts("No Solution");
        else
            printf("%d\n", ub);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/neweryyy/article/details/114819464