#include using namespace std; const int N = 30, M = 100; int n; // n个合格的申请人申请岗位 int r[N]; // 各个时间段需要的人员数量 int num[N]; // 第i个申请人可以从num[i]时刻开始连续工作8小时 int dist[N]; // 最长距离,本题是求“最少需要雇佣”,所以是最长路 int cnt[N]; // 用于判正环(最长路) bool st[N]; // spfa专用是否在队列中的标识 // 邻接表 int e[M], h[N], idx, w[M], ne[M]; 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) { // 每次清空邻接表 memset(h, -1, sizeof h); idx = 0; // s(i):从1点到i点,需要雇佣的人员数量 for (int i = 1; i <= 24; i++) { add(i - 1, i, 0); // s(i) >= s(i-1) + 0 add(i, i - 1, -num[i]); // s(i-1) >= s(i)-num[i] } // s(i) >= s(i-8) + r(i) for (int i = 8; i <= 24; i++) add(i - 8, i, r[i]); // s(i)>=s(i+16)−s(24)+r(i) for (int i = 1; i <= 7; i++) add(i + 16, i, -c + r[i]); // s24的引入,需要再加两个不等式 s(24)=c add(0, 24, c); // s(24)>=c -> s(24) >= c +s(0) // -> s(24) >= s(0) + c add(24, 0, -c); // s(24)<=c -> s(24) <= c +s(0) // -> s(0) >= s(24) -c } // spfa找正环 bool spfa(int c) { build(c); // 建图 // 每次初始化 memset(st, 0, sizeof st); memset(cnt, 0, sizeof cnt); memset(dist, -0x3f, sizeof dist); queue q; // 超级源点大法好~ for (int i = 0; i <= 24; i++) { q.push(i); st[i] = true; } while (q.size()) { int u = q.front(); q.pop(); st[u] = false; for (int i = h[u]; ~i; i = ne[i]) { int v = e[i]; if (dist[v] < dist[u] + w[i]) { // 最长路 dist[v] = dist[u] + w[i]; cnt[v] = cnt[u] + 1; // 一共24个点,发现正环了则返回true if (cnt[v] >= 25) return true; if (!st[v]) { q.push(v); st[v] = true; } } } } return false; } int main() { int T; scanf("%d", &T); while (T--) { // 各个时间段收银员最小需求数量的清单 // 这里为了使用前缀和,向后进行了错一位操作 for (int i = 1; i <= 24; i++) scanf("%d", &r[i]); scanf("%d", &n); // n个合格的申请人申请岗位 memset(num, 0, sizeof num); // 多组测试数据,所以需要每次清零 for (int i = 0; i < n; i++) { int t; scanf("%d", &t); // 申请人可以从num[t+1]时刻开始连续工作8小时 num[t + 1]++; //++代表这个时段可以干活的人数+1 } // 二分总人数 int l = 0, r = n; // 雇佣的人员,最少是0,最多是1000 // 人员雇佣的越多,肯定越能满足用工要求,但成本会高 // 所以,存在单调性,可以二分 while (l < r) { int mid = (l + r) >> 1; if (!spfa(mid)) // 如果不等式组有解,向左逼近 r = mid; else l = mid + 1; // 无解向右逼近 } if (spfa(l)) // 如果最终计算出来的结果还是无解,那就是无解 puts("No Solution"); else printf("%d\n", l); // 输出最小值 } return 0; }