题目描述
假设银行有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++){ //当预处理时间<=当前时间时,即对应窗口的客户业务已处理完,popif(winTime[i] <= time && !que[i].empty()){que[i].pop();}}while(!queVip.empty() && client[queVip.front()][3] != -1){ //对已经处理的vip客户 popqueVip.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;
}