链接:
1014 Waiting in Line - PAT (Advanced Level) Practice (pintia.cn)
大致题意:
- 有
n
个窗口,每个窗口最多能容纳m
人同时排队。 - 一共有
k
个顾客,他们每个人有一个服务时长t[i]
。 - 顾客们从早上 8 点开始服务。
- 如果一个顾客在下午 5 点(即 17:00)还没有开始服务,那么他不会被服务(输出 "Sorry"),否则就会服务到完成。
如果一个客户在17:00以及以后还没有开始服务就不再服务输出sorry;如果这个服务已经开始了,无论时间多长都要等他服务完毕。
基本思路:
代码的主要流程:
小时:分钟不好比较,可以先转为分钟,最后根据格式化来输出即可。
-
模拟顾客排队的过程:
- 使用一个
deque<int> deq[22]
数组来模拟每个窗口的队列,最多 22 个窗口(n
不会超过 22)。 - 对于每个顾客,根据以下规则安排排队:
- 首先找到队伍人数最少的窗口
p
。 - 如果当前选择的窗口队伍已经满了(队列长度达到
m
),需要找到队列最早有空位的窗口,将该窗口的最早服务结束的顾客移出队列。 - 将当前顾客加入所选的窗口,并根据窗口最后一个顾客的结束时间来计算他的开始时间和结束时间。
- 首先找到队伍人数最少的窗口
- 使用一个
-
顾客入队逻辑:
- 每当一个顾客加入队列时,如果队列不为空,那么他的服务开始时间是队列中最后一个顾客的服务结束时间之后,计算该顾客的服务结束时间。
-
查询处理:
- 查询部分根据输入的顾客编号
x
,判断该顾客的服务是否在 17:00 之前开始。如果没有在 17:00 之前开始服务,输出 "Sorry",否则输出该顾客服务结束的具体时间。
- 查询部分根据输入的顾客编号
#include<bits/stdc++.h>
using namespace std;int finish[1010], start[1010], t[1010];
deque<int> dq[22]; // 每个窗口的队列
int Long = 9 * 60; // 表示17:00 (540分钟)int main() {int n, m, k, q; cin >> n >> m >> k >> q;for (int i = 1; i <= k; i++) {cin >> t[i]; // 输入每个顾客的服务时间// 为顾客选择人数最少的窗口int p = 1;for (int j = 2; j <= n; j++) {if (dq[j].size() < dq[p].size()) p = j; // 找到队伍人数最少的窗口}// 如果队伍已满,选择服务最早结束的窗口if (dq[p].size() == m) {for (int j = 1; j <= n; j++) {if (!dq[j].empty()) { // 确保队列不为空int Inidx = dq[j].front();if (finish[Inidx] < finish[dq[p].front()]) { // 找到最早结束的顾客p = j;}}}dq[p].pop_front(); // 服务结束的顾客出队}// 计算当前顾客的服务开始时间和结束时间int last = 0;if (!dq[p].empty()) last = dq[p].back(); // 获取队列最后一个顾客start[i] = finish[last]; // 当前顾客的开始时间是最后一个顾客的结束时间finish[i] = start[i] + t[i]; // 当前顾客的结束时间dq[p].push_back(i); // 将当前顾客加入队列}while (q--) {int x;cin >> x; if (start[x] >= Long) {cout << "Sorry\n"; // 如果开始时间在17:00之后,输出Sorry} else {printf("%02d:%02d\n", 8 + finish[x] / 60, finish[x] % 60);}}return 0;
}
疑问?
为什么可以使用双端队列?
因为在我们计算顾客的开始时间和结束时间的时候,需要根据当前窗口最后一个顾客的结束时间作为开始时间,我们需要频繁的获取队列中最后一个顾客,所以使用双端队列不失为一个好方法。
输出的格式表示什么意思?
printf("%02d:%02d\n", ...)
的作用是将小时和分钟格式化为 hh:mm
的形式,如果小时或分钟不足两位,则前面补零。
%02d
:这是 printf
函数中的格式控制符,用于以两位数字输出,如果数字只有一位,则在前面补零。例如,输出 08:05
而不是 8:5
。
服务时间是基于早上 8 点开始的,因此小时部分需要加上 8
。