4-4 D. 银行排队问题之单队列多窗口加VIP服务

题目描述

假设银行有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

思路 

 根据样例分析:4-4 D. 银行排队问题之单队列多窗口加VIP服务_第1张图片

a、设置各窗口预计处理时间(用来表示小括号中的内容),便于得到时间轴与最后完成时间

b、将每个窗口作为一个队列,K个窗口用队列数组表示

c、对VIP客户,处于等待状态时,设置queVip队列,便于处理

d、根据更新的时间轴,更新每个窗口客户开始处理push、客户处理完成pop、客户已到达开始等待push、客户开始处理退出等待pop

e、对于客户的到达时间、处理业务时间、是否VIP信息用二维数组存储,并增加一个等待时间,初始值为-1(若此值为-1即客户业务还未被处理,若 != -1 则客户已经完成业务)

代码 

#include 
#include 
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 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;
}

你可能感兴趣的:(数据结构,算法,c++,数据结构)