1014 Waiting in Line (30分)
Suppose a bank has N windows open for service. There is a yellow line in front of the windows which devides the waiting area into two parts. The rules for the customers to wait in line are:
- The space inside the yellow line in front of each window is enough to contain a line with M customers. Hence when all the N lines are full, all the customers after (and including) the (NM+1)st one will have to wait in a line behind the yellow line.
- Each customer will choose the shortest line to wait in when crossing the yellow line. If there are two or more lines with the same length, the customer will always choose the window with the smallest number.
- Customeri will take Ti minutes to have his/her transaction processed.
- The first N customers are assumed to be served at 8:00am.
Now given the processing time of each customer, you are supposed to tell the exact time at which a customer has his/her business done.
For example, suppose that a bank has 2 windows and each window may have 2 custmers waiting inside the yellow line. There are 5 customers waiting with transactions taking 1, 2, 6, 4 and 3 minutes, respectively. At 08:00 in the morning, customer1 is served at window1 while customer2 is served at window2. Customer3 will wait in front of window1 and customer4 will wait in front of window2. Customer5 will wait behind the yellow line.
At 08:01, customer1 is done and customer5 enters the line in front of window1 since that line seems shorter now. Customer2 will leave at 08:02, customer4 at 08:06, customer3 at 08:07, and finally customer5 at 08:10.
Input Specification:
Each input file contains one test case. Each case starts with a line containing 4 positive integers: N (≤20, number of windows), M (≤10, the maximum capacity of each line inside the yellow line), K (≤1000, number of customers), and Q (≤1000, number of customer queries).
The next line contains K positive integers, which are the processing time of the K customers.
The last line contains Q positive integers, which represent the customers who are asking about the time they can have their transactions done. The customers are numbered from 1 to K.
Output Specification:
For each of the Q customers, print in one line the time at which his/her transaction is finished, in the format HH:MM
where HH
is in [08, 17] and MM
is in [00, 59]. Note that since the bank is closed everyday after 17:00, for those customers who cannot be served before 17:00, you must output Sorry
instead.
Sample Input:
2 2 7 5
1 2 6 4 3 534 2
3 4 5 6 7
Sample Output:
08:07
08:06
08:10
17:00
Sorry
一、试题分析:
本题为一道模拟题:现实生活中银行中排队接受柜台服务(银行服务时间为8:00-17:00)的问题
- 银行中有n个窗口,每个窗口最大排队人数为m人;
- 共k名顾客,q名查询顾客(提供查询顾客的编号);
- 当某一个窗口的第一人结束服务,若黄线外有顾客等待,则进入最短的窗口队列,最后要求出每个查询顾客完成业务的时间。
二、解题思路:
首先要知道每个顾客在哪个窗口中办理业务、进队出队的时间需要密切相连(所以对每一个窗口设置一个队列queue),由于银行服务时间在8:00-17:00,所以精确到每一分钟顺序遍历每个窗口看哪个顾客完成业务(所有可进入黄线内的顾客已知在哪个窗口队列中;只要线内有人离开,黄线外的顾客进入该队列)
- 如何制定数据结构?
- 定义顾客结构体:每个顾客有许多信息,封装到一起便于使用(要初始化每个顾客的参数)
- 定义n个窗口队列:便于获取每个队列队首顾客的结束业务时间(line[i].front().time)
- 定义1个等待队列:便于线外等待顾客进入线内
- 具体算法是什么样的?
- 将所有顾客信息存储到相关结构中:
- 前n*m位顾客:存储到对应窗口队列中(各窗口第一位顾客已知服务开始时间和结束时间,先初始化)
- 剩余顾客:存储到线外等待队列中
- 若还有顾客需要办理业务 & 在营业时间范围内循环遍历(这两点即为循环条件):
- 时间从0开始的,所以首先t1++(外层循环):
- 对n窗口依次判断(内层循环):
(2.1)队首顾客是否完成业务:已进入线内且若结束(该顾客的结束时间==当前时间)
(2.1.1)顾客出队:不仅从对应队列中弹出,还要总顾客人数减一
(2.1.2)顾客数组记录该顾客时间信息:便于之后输出结果
(2.1.3)更新队首的开始时间和结束时间:这样才能实现队列每一个人时间上的连接(为了下面的情况)
(2.1.4)等待队列补上一人
(2.2)队首顾客是否完成业务:已进入线内但到点17:00(该顾客的结束时间>营业结束时间)
(2.2.1)顾客出队:不仅从对应队列中弹出,还要总顾客人数减一(仍继续办理业务)
(2.2.2)顾客数组记录该顾客时间信息:便于之后输出结果
(2.2.3)更新队首的开始时间和结束时间:这样才能实现队列每一个人时间上的连接(为了下面的情况)
(2.2.4)不再继续办理业务
- 输出查询结果
- 结果为-1:输出Sorry(首字母大写)
- 按照规定格式输出:
- 时、分均为两位,高位补0:使用printf输出
- 上面的算法求得的是总分钟数:取模、取余计算时、分
#include <iostream>
#include <queue>
using namespace std;
//银行顾客包含很多的信息,存入结构体中方便使用
struct Customer{
int id; //编号
int serve; //服务时间
int start; //开始时间
int end; //结束时间
Customer(): start(0), end(-1), serve(0), id(0){}
}customer[1001];
int main()
{
int n; //窗口数
int m; //窗口容量
int k; //总客户数
int q; //查询客户数
cin>>n>>m>>k>>q;
queue<Customer> line[n+1]; //n个窗口的队列
queue<Customer> wait; //等待队列
for(int i=1;i<=k;i++){ //先按顺序将窗口排满
cin>>customer[i].serve;
customer[i].id=i;
if(i<=n){ //作为后面递推的起始数据
customer[i].start=0;
customer[i].end=customer[i].serve;
}
if(i<=n*m){
line[(i-1)%n+1].push(customer[i]);
}else{
wait.push(customer[i]);
}
}
int t1=0; //营业时间
int t2=540; //关闭时间
for(;t1<t2&&k>0;){
t1++;
//n个窗口依次判断是否有人完成服务
for(int i=1;i<=n;i++){
if(line[i].empty()){ //如果为空,后面肯定无人等待否则会接上队列
continue;
}
Customer cus=line[i].front(); //仅获取该队列第一位顾客的信息(cus是独立的,与customer数组无关)
//该队列此人可以继续完成交易
if(t1==cus.end||cus.end>t2){
//弹出队列
line[i].pop();
k--;
//记录本人的开始和离开时间
customer[cus.id].start=cus.start;
customer[cus.id].end=cus.end;
//该队列原第一人已经离开,更新现第一人的相关信息
line[i].front().start=cus.end;
line[i].front().end=line[i].front().start+line[i].front().serve;
if(!wait.empty()){
line[i].push(wait.front());
wait.pop();
}
}
}
}
int query; //查询客户编号
for(int i=1;i<=q;i++){
cin>>query;
if(customer[query].end==-1){
cout<<"Sorry"<<endl;
}else{
printf("%02d:%02d\n",customer[query].end/60+8,customer[query].end%60);
}
}
return 0;
}
来源:CSDN
作者:Ariel_x
链接:https://blog.csdn.net/Ariel_x/article/details/104071425