1014 Waiting in Line (30 分)
题目描述
本题是一道模拟题。一个银行有 N
个窗口,每个窗口前面最多能排 M
个人。银行每天 8:00
开始处理业务,17:00
结束接待任务,但是不会终止正在执行的任务。每个人都有编号,编号小的拥有优先选择权。如果一个人看到有很多窗口都是空的,那么选择队伍短的排队;如果队伍长度相同,则选择编号小的队伍。如果当天的人总数多于 N*M
,则多余的人在外等候,只要有一个人业务处理结束,那么在外等候的人中编号最小的插入到业务结束的人所在队列的末尾。
题目会给定银行窗口个数 N
,窗口最大容量 M
,当天顾客总数 K
,同时给出每个用户办理业务的时间共 K
个。在 8:00~17:00
之间需要知道每个人的业务是否被处理,如果是是则输出结束时间,格式为 HH:MM
(如08:10
13:00
等);如果没有完成则输出 Sorry
。题目中还会给出要查询的人的个数 Q
以及每个人的编号。
问题分析
由于题目中希望输出的时间,且精确到分,因此一天银行工作的时间是 540min
,然后对于每个人,一旦受理任务则记录下时间,一旦结束任务则用受理时间加上持续时间即为结束时间,同时将此编号退出队列,并且让外面队列的人中编号最小的加入到该队列,依次重复。需要注意的是,总共有N
个窗口,每个窗口是互不影响的。
问题解决流程
- 读入数据,对所有人初始化为
Sorry
; - 新建
N
个队列并进行初始化(即让N*M
个人全部进去); - 开始处理业务,有人结束则有人进入(如果外面有人的话);
- 时间到,不进行进入队列,不办理新业务,处理正在进行的任务;
- 根据输入对需要输出的转换为
HH:MM
格式; - 结束。
代码实现
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int time[1005],finish[1005];
queue<int> Q[25];
int main(void){
//N:窗口数;M:每个窗口的最大容量;K:顾客数;Q:每个用户的查询次数
int n,m,k,x,q;
cin>>n>>m>>k>>q;
//读取每个用户的时间
for(int i=1;i<=k;++i) cin>>time[i];
int sum=0,cnt=1;
for(int t=0;t<540;++t){//只处理在上班时间范围内的顾客
while(sum<n*m&&cnt<=k){//先让所有人先进去(总人数为小于黄线区域内可以容纳的人数)
int id=0;//第id个窗口队伍最短
for(int i=0;i<n;++i){
if(Q[i].size()<Q[id].size()) id=i;//有更短的窗口
if(Q[id].size()==0) finish[cnt]=t+time[cnt];//该窗口没人,标记第cnt个人的结束时间
if(Q[id].size()<m&&cnt<=k){//准备处理下一个人
Q[id].push(cnt);
cnt++;
sum++;
}
}
}
for(int i=0;i<n;++i){//n个窗口
for(int j=0;j<Q[i].size();++j){
if(t==finish[Q[i].front()]){//第i个窗口的结束时间为当前时间t
Q[i].pop();--sum;
if(!Q[i].empty()){//记录当前窗口的下一个顾客的结束时间
int tmp=Q[i].front();
finish[tmp]=t+time[tmp];
}
}
}
}
}
//格式化输出
for(int i=0;i<q;++i){
cin>>x;
if(finish[x]==0) printf("Sorry");
else printf("%02d:%02d\n",8+finish[x]/60,finish[x]%60);
}
return 0;
}