题目链接:点击这里
题意:假设一家银行有 N N N 个窗口在提供服务。窗口前有一条黄线,将等候区分成两部分。顾客排队的规则是:
-
每个窗口前面的黄线内的空间足够容纳 M M M 个客户。因此,当所有的 N N N 个队伍都满了时,所有在 ( N ∗ M + 1 ) (N*M+1) (N∗M+1) 之后(包括)的客户将不得不在黄线后面排队等候。
-
过黄线时,每位顾客都会选择最短的队伍等候。如果有两个或两个以上长度相同的窗口,客户总是会选择窗口编号更小的窗口。
-
客户 i i i 将花费 T i T_i Ti 的时间处理他/她的事务。
-
假定第一批顾客的服务时间是上午 8 点。
现在,给定每个客户的处理时间,您应该知道客户完成其业务的确切时间。
坑:如果一个客户的业务结束时间超过 17:00,这并不代表其无法完成服务。只要他在 17:00 前开始被服务,银行就必须给他服务完才能下班。
比如,有一个客户在 16:58 时才开始接受服务,哪怕他的业务办理时长为 60 60 60 分钟,银行也要给他办理完才能下班,这也与现实生活相符。所以,我们要看的是开始服务时间是否超过 17:00,而不是结束时间!
思路: N N N 个窗口用 N N N 个队列进行维护,记录每个顾客的开始服务时间、结束服务时间、业务办理时长,最后判断开始时间是否超过了 17 : 00 17:00 17:00,按要求输出即可。
注意:hh:mm
时间都转化为分钟,即 8:00 是 0 0 0,8:01 是 1 1 1,…,17:00 是 540 540 540。
AC代码:
#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
struct node
{
int cost, start, end;
}a[1010];
queue<node> q[25];
int main()
{
// N个窗口,编号为1~N
// 每个窗口最多排M个人
// K个客户,编号为1~K
// Q个询问
int N, M, K, Q;
scanf("%d%d%d%d", &N, &M, &K, &Q);
for(int i = 1; i <= K; ++i) scanf("%d", &a[i].cost);
for(int i = 1; i <= K; ++i)
{
if(i <= N * M) // 初始,前N*M个人直接进黄线排队
{
int wid = (i - 1) % N + 1; // 排到wid号窗口后面
if(i <= N) a[i].start = 0; // 前N个人开始时间为0
else a[i].start = q[wid].back().end; // 否则,开始时间是上一个人的结束时间
a[i].end = a[i].start + a[i].cost;
q[wid].push(a[i]);
}
else
{
int wid = 1;
for(int j = 2; j <= N; ++j)
{
if(q[j].front().end < q[wid].front().end)
wid = j;
}
q[wid].pop();
// 当前此人排到wid号窗口后面
a[i].start = q[wid].back().end;
a[i].end = a[i].start + a[i].cost;
q[wid].push(a[i]);
}
}
while(Q--)
{
int id;
scanf("%d", &id);
// 如果开始服务时间超过了银行关门时间,则无法服务
if(a[id].start >= 540) puts("Sorry");
else printf("%02d:%02d\n", a[id].end / 60 + 8, a[id].end % 60);
}
return 0;
}
微信公众号《算法竞赛求职》,致力于详细讲解竞赛和求职所涉及到的算法原理和模板。欢迎关注,一起交流进步!