POJ - Problem 1275 - Cashier Employment

· 对于差分约束,题目要求求什么便设什么,令Sum[i]表示由0 ~ i的雇佣人数。

· 要充分利用题目所给条件,令Have[i]表示i时刻申报的人数,Need[i]表示i时刻需要的人数「结合 “人数” 关键词」。

此时容易列出两个基本不等式:

    Sum[i] - Sum[i - 1] >= 0;
    Sum[i] - Sum[i - 1] <= Have[i];

此时发现还有Need[]和范围为8个单位长度的区间没有使用,可得:

    Sum[i] - Sum[i - 8] >= Need[i]; (i >= 8)

那么还有环形无法处理。

对于环形的处理:

将整个24个单位的区间以当前点为分割点,将大区间分割为(i - 8 + 24) ~ i (环形)以及i ~ i + 16,相当于覆盖了整个环形区间。

相当于是去限制非当前考虑的完整的区间从而达到限制当前因环形而断开的区间。

所以此时仅需考虑两个区间间的限制即可。

并且需要一个Sum[- 1]。

答案显然满足单调性,故考虑二分。

扫描二维码关注公众号,回复: 3329748 查看本文章

令mid表示需要mid个服务员。

则可列方程:

    mid - (Sum[i + 16] - Sum[i]) >= Need[i]; (i < 8)

即可解答。

· 代码:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <queue>
  5 
  6 using namespace std;
  7 
  8 const int MAXN = 1000 + 10;
  9 const int MAXM = MAXN * 10;
 10 const int MAXT = 24 + 10;
 11 
 12 struct LinkedForwardStar {
 13     int to;
 14     int w;
 15 
 16     int next;
 17 } ;
 18 
 19 LinkedForwardStar Link[MAXM << 1];
 20 int Head[MAXT]= {0};
 21 int size = 0;
 22 
 23 void Insert (int u, int v, int w) {
 24     Link[++ size].to = v;
 25     Link[size].w = w;
 26     Link[size].next = Head[u];
 27 
 28     Head[u] = size;
 29 }
 30 
 31 int T;
 32 
 33 int N;
 34 
 35 int Have[MAXT];
 36 int Need[MAXN];
 37 
 38 int Dist[MAXT];
 39 int Count[MAXT];
 40 
 41 queue<int> Que;
 42 bool Inque[MAXT];
 43 
 44 bool SPFA (int mid) {
 45     memset (Dist, 0xcf, sizeof (Dist));
 46     memset (Count, 0, sizeof (Count));
 47     memset (Inque, 0, sizeof (Inque));
 48     while (! Que.empty())
 49         Que.pop();
 50 
 51     Que.push(24);
 52     Inque[24] = true;
 53     Dist[24] = 0;
 54 
 55     while (! Que.empty()) {
 56         int u = Que.front();
 57         Que.pop();
 58 
 59         Inque[u] = false;
 60         Count[u] ++;
 61 
 62         if (Count[u] >= 25)
 63             return false;
 64 
 65         for (int i = Head[u]; i; i = Link[i].next) {
 66             int v = Link[i].to, w = Link[i].w;
 67 
 68             if (Dist[u] + w > Dist[v]) {
 69                 Dist[v] = Dist[u] + w;
 70 
 71                 if (! Inque[v]) {
 72                     Que.push(v);
 73                     Inque[v] = true;
 74                 }
 75             }
 76         }
 77     }
 78 
 79     return Dist[23] == mid;
 80 }
 81 
 82 bool Check (int mid) {
 83     memset (Head, 0, sizeof (Head));
 84     size = 0;
 85 
 86     Insert (24, 23, mid);
 87     Insert (24, 0, 0);
 88     Insert (0, 24, - Have[0]);
 89     for (int i = 1; i <= 23; i ++) {
 90         Insert (i - 1, i, 0);
 91         Insert (i, i - 1, - Have[i]);
 92     }
 93     for (int i = 8; i <= 23; i ++)
 94         Insert (i - 8, i, Need[i]);
 95     for (int i = 0; i < 8; i ++)
 96         Insert (i + 16, i, Need[i] - mid);
 97 
 98     return SPFA (mid);
 99 }
100 
101 int main () {
102     scanf ("%d", & T);
103 
104     for (int Case = 1; Case <= T; Case ++) {
105         memset (Have, 0, sizeof (Have));
106 
107         for (int i = 0; i <= 23; i ++)
108             scanf ("%d", & Need[i]);
109 
110         scanf ("%d", & N);
111 
112         for (int i = 1; i <= N; i ++) {
113             int start;
114             scanf ("%d", & start);
115 
116             Have[start] ++;
117         }
118 
119         bool flag = false;
120         int left = 0, right = N;
121         while (left < right) {
122             int mid = (left + right) >> 1;
123 
124             if (Check (mid)) {
125                 flag = true;
126                 right = mid;
127             }
128             else
129                 left = mid + 1;
130         }
131 
132         if (! flag)
133             puts ("No Solution");
134         else
135             printf ("%d\n", left);
136     }
137 
138     return 0;
139 }
140 
141 /*
142 1
143 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
144 5
145 0
146 23
147 22
148 1
149 10
150 */

猜你喜欢

转载自www.cnblogs.com/Colythme/p/9696565.html