题意
传送门 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[i−1]S[i]−S[i−1]≤num[i]S[i]−S[j]≥{
R[i]R[i]−(S[23]−S[−1])i>ji<j,j=(i−8+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[i−1]−S[i]≤0S[i]−S[i−1]≤num[i]S[j]−S[i]≤{
−R[i]x−R[i]i>ji<j,j=(i−1−8+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;
}