题目描述
假设银行有K个窗口提供服务,窗口前设一条黄线,所有顾客按到达时间在黄线后排成一条长龙。当有窗口空闲时,下一位顾客即去该窗口处理事务。当有多个窗口可选择时,假设顾客总是选择编号最小的窗口。
有些银行会给VIP客户以各种优惠服务,例如专门开辟VIP窗口。为了最大限度地利用资源,VIP窗口的服务机制定义为:当队列中没有VIP客户时,该窗口为普通顾客服务;当该窗口空闲并且队列中有VIP客户在等待时,排在最前面的VIP客户享受该窗口的服务。同时,当轮到某VIP客户出列时,若VIP窗口非空,该客户可以选择空闲的普通窗口;否则一定选择VIP窗口。
本题要求输出前来等待服务的N位顾客的平均等待时间、最长等待时间、最后完成时间,并且统计每个窗口服务了多少名顾客。
输入
输入第1行给出正整数N(≤1000),为顾客总人数;随后N行,每行给出一位顾客的到达时间
T
、事务处理时间P
和是否VIP的标志(1是VIP,0则不是),并且假设输入数据已经按到达时间先后排好了顺序;最后一行给出正整数K(≤10)—— 为开设的营业窗口数,以及VIP窗口的编号(从0到K−1)。这里假设每位顾客事务被处理的最长时间为60分钟。输入样例:
10
0 20 0
0 20 0
1 68 1
1 12 1
2 15 0
2 10 0
3 15 1
10 12 1
30 15 0
62 5 1
3 1
输出
在第一行中输出平均等待时间(输出到小数点后1位)、最长等待时间、最后完成时间,之间用1个空格分隔,行末不能有多余空格。
在第二行中按编号递增顺序输出每个窗口服务了多少名顾客,数字之间用1个空格分隔,行末不能有多余空格。
输出样例:
15.1 35 67
4 5 1
思路
根据样例分析:
a、设置各窗口预计处理时间(用来表示小括号中的内容),便于得到时间轴与最后完成时间
b、将每个窗口作为一个队列,K个窗口用队列数组表示
c、对VIP客户,处于等待状态时,设置queVip队列,便于处理
d、根据更新的时间轴,更新每个窗口客户开始处理push、客户处理完成pop、客户已到达开始等待push、客户开始处理退出等待pop
e、对于客户的到达时间、处理业务时间、是否VIP信息用二维数组存储,并增加一个等待时间,初始值为-1(若此值为-1即客户业务还未被处理,若 != -1 则客户已经完成业务)
代码
#include <iostream>
#include <queue>
using namespace std;
int main()
{
int N,K,VIP;
cin >> N;
int client[N][4];
for(int i = 0; i < N; i++){ //输入数据
for(int j = 0; j < 3; j++){
cin >> client[i][j];
client[i][3] = -1; //等待时间
if(j == 1 && client[i][j] > 60){ //每位顾客事务被处理的最长时间为60分钟
client[i][j] = 60;
}
}
}
cin >> K >> VIP;
queue<int> que[K],queVip; //que[K] k个窗口,queVip VIP客户的等候队伍
int winTime[K],waitNum[K]; //winTime窗口预处理时间 waitNum窗口处理客户数
for(int i = 0; i < K; i++){
winTime[i] = 0;
waitNum[i] = 0;
}
int time = 0,vipFlag=-1; //time当前时间
while(1){
for(int i = 0; i < K; i++){ //当预处理时间<=当前时间时,即对应窗口的客户业务已处理完,pop
if(winTime[i] <= time && !que[i].empty()){
que[i].pop();
}
}
while(!queVip.empty() && client[queVip.front()][3] != -1){ //对已经处理的vip客户 pop
queVip.pop();
}
int v = 0; //记录已经处于等待状态的客户的末位
for(int i = 0; i < N; i++){
if(client[i][0] <= time){
v++;
if(client[i][2] == 1 && i > vipFlag){ //处于等待的VIP客户入queVip队列,vipFlag确保不重复入队
queVip.push(i);
vipFlag = i;
}
}else{
break;
}
}
if(que[VIP].empty() && !queVip.empty()){ //若vip窗口为空,且有vip客户正在等待
que[VIP].push(queVip.front());
waitNum[VIP]++; //该窗口接待客户人数++
client[queVip.front()][3] = time - client[queVip.front()][0]; //得到这一客户的等待时间
if(winTime[VIP] == 0){ //若预处理时间为0,说明之前还未有客户来过这一窗口,要注意加上已经过去的时间
winTime[VIP] = client[queVip.front()][0] + client[queVip.front()][1];
}else{
winTime[VIP] += client[queVip.front()][1];
}
queVip.pop();
}
for(int i = 0; i < K; i++){ //普通窗口的处理
if(que[i].empty()){
for(int j = 0; j < N; j++){
if(client[j][0] <= time) {
if(client[j][3] == -1){
que[i].push(j);
waitNum[i]++;
client[j][3] = time - client[j][0];
if (winTime[i] == 0) {
winTime[i] = client[j][0] + client[j][1];
} else {
winTime[i] += client[j][1];
}
break;
}
}else{
break;
}
}
}
}
int flag = 0, min = 9999, sumPeo=0;;
for(int i = 0; i < K; i++){
sumPeo += waitNum[i];
if(winTime[i] == 0){
flag = 1;
}
if(min > winTime[i]){
min = winTime[i];
}
}
if(sumPeo == N){ //所有客户处理完成,退出循环
break;
}
if(flag == 1 || min == time){ //更新时间
time = client[v][0];
}else{
time = min;
}
}
//输出
int max=-1, final, sum=0;
double aver;
for(int i = 0; i < N; i++){
sum += client[i][3];
if(client[i][3] > max){
max = client[i][3];
}
}
aver = sum * 1.0 / N;
int waitFinal=0;
for(int i = 0; i < K;i++){
if(waitFinal < winTime[i]){
waitFinal = winTime[i];
}
}
cout << aver << " " << max << " " << waitFinal << endl;
for(int i = 0; i < K; i++){
cout << waitNum[i];
if(i != K-1){
cout << " ";
}
}
return 0;
}