7-5 银行排队问题之单队列多窗口加VIP服务 (8分)优先队列

7-5 银行排队问题之单队列多窗口加VIP服务 (8分)
假设银行有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分钟。
输出格式:

在第一行中输出平均等待时间(输出到小数点后1位)、最长等待时间、最后完成时间,之间用1个空格分隔,行末不能有多余空格。

在第二行中按编号递增顺序输出每个窗口服务了多少名顾客,数字之间用1个空格分隔,行末不能有多余空格。
输入样例:

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

输出样例:

15.1 35 67
4 5 1
理解:
1.队列在随时间不断变化, 是以时间为天然的序
2.vip可以插队,vip在一个队列时如果有vip柜台空闲那么vip人员不管在队列中那个位置都直接去办理业务
思路:可以以时间为天然的序, 来进行处理,但要注意vip与vip柜台的对应
思考:对于这种大模拟,我们最好在开始时,进行模拟一次,理解模拟规则, 再按照某个方向进行模拟,而本题中直接就有时间这个序,可以直接for(int i = 0; i ; i ++)循环
在我的代码中对该方法进行了优化,使其不会循环不会使用的时间点, 但也导致使用了太多的STL容器, 其结果并不见得优化了多少

#include<bits/stdc++.h>

using namespace std;
const int N = 1101;
int n, k, vip_adress = 0, num[N], max_wait, last_complete, vis[N];//标记是否已经被服务
double all_wait;
struct node
{
    
    
    int arrive_time;
    int solve_time;
    bool vis;
}customers[N];

struct counter
{
    
    
    int id;
    int start;
    int end_time;
    bool operator <(const counter &x)const
    {
    
    
        if(end_time != x.end_time) return end_time > x.end_time;
        return id > x.id;
    }
}counters[11];
priority_queue<counter> q;//优先队利存储柜台
void get_ans(int x, int y) // 将第y个人放入第x个柜台
{
    
    
    counters[x].start = max(customers[y].arrive_time, counters[x].end_time);
    counters[x].end_time = counters[x].start + customers[y].solve_time;
    int x1 = counters[x].start - customers[y].arrive_time;
    num[x] ++;
    max_wait = max(x1, max_wait);
    last_complete = max(last_complete, counters[x].end_time);
    all_wait += x1;
}
int main()
{
    
    
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
    
    
        cin >> customers[i].arrive_time >> customers[i].solve_time >> customers[i].vis;
        customers[i].solve_time = customers[i].solve_time > 60?60:customers[i].solve_time;
    }
    cin >> k >> vip_adress;
    vip_adress ++;//(0, k - 1)
    for(int i = 1; i <= k; i++)
    {
    
    
        counters[i].id = i;
        q.push(counters[i]);
    }
    int rear = 1, pre = 1; //创建队列
    while(rear <= n)
    {
    
    
        int x = q.top().id;
        vector<counter> qual; // 找当前可能用到的柜台
        bool flag1 = false;//判断相同时间内有无空闲的vip房间
        while(vis[rear] == 1) rear ++;//在队列中还没有完成的人的
        while(pre <= n && counters[x].end_time >= customers[pre].arrive_time)    pre ++;// 更新有多少人放入队列
        if(rear >= pre) pre = rear + 1; // 到达终点rear -> n
        if(rear > n) break;
        while(q.size() > 0 && (q.top().end_time == counters[x].end_time && counters[x].end_time >= customers[rear].arrive_time) || (counters[x].end_time <= customers[rear].arrive_time && q.top().end_time <= customers[rear].arrive_time)) //将可能用到的柜台放入数组
        {
    
    //找可能使用的柜台时间相等时,还要注意vip房间
            //1如果当前的第一个可能使用的人的到达时间小于最早结束时间, 后序相等的柜台都进
            //2如果当前的第一个人到达的时间大于柜台最早结束的时间, 那么在他到达之前的时间内空闲的柜台都进
            qual.push_back(q.top());
            if(q.top().id == vip_adress)
            {
    
    
                flag1 = true;//标记是否有vip柜台
                q.pop();
                break;
            }
            q.pop();
        }

        if(counters[x].end_time < customers[rear].arrive_time) //当前的第一个人到达的时间大于柜台最早结束的时间
        {
    
    
            while(pre <= n && customers[pre].arrive_time == customers[rear].arrive_time) // 更新所有相等的人
                pre ++;
        }
        bool flag = false;
        int id_vip = 0;
        for(int i = rear; i < pre; i++)//判断有无vip人
            if(customers[i].vis && vis[i] == 0)
            {
    
    
                id_vip = i, flag = true;
                break;
            }
        if(flag1 && flag)//如果是vip且该房间是vip房间
        {
    
    
            get_ans(vip_adress, id_vip);
            for(int i = 0; i < qual.size() - 1; i++) q.push(qual[i]);
            q.push(counters[vip_adress]);
            vis[id_vip] = 1;
        }
        else
        {
    
    
            if(rear <= n)
            {
    
    
                get_ans(x, rear);
                for(int i = 1; i < qual.size(); i++)    q.push(qual[i]);
                q.push(counters[x]);
                vis[rear] = 1;
                rear ++;
            }
            else
                break;
        }
    }
    printf("%.1f %d %d\n", all_wait/n, max_wait, last_complete);
    for(int i = 1; i <= k; i++) printf("%d%c", num[i], i == k ? '\n':' ');
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45778406/article/details/108915287