7-13 银行排队问题之单队列多窗口加VIP服务

题目描述

假设银行有K个窗口提供服务,窗口前设一条黄线,所有顾客按到达时间在黄线后排成一条长龙。当有窗口空闲时,下一位顾客即去该窗口处理事务。当有多个窗口可选择时,假设顾客总是选择编号最小的窗口。
本题要求输出前来等待服务的N位顾客的平均等待时间、最长等待时间、最后完成时间,并且统计每个窗口服务了多少名顾客。

输入格式:

输入第1行给出正整数N(≤1000),为顾客总人数;随后N行,每行给出一位顾客的到达时间T和事务处理时间P,并且假设输入数据已经按到达时间先后排好了顺序;最后一行给出正整数k(≤10),为开设的营业窗口数。这里假设每位顾客事务被处理的最长时间为60分钟。

输出格式:

在第一行中输出平均等待时间(输出到小数点后1位)、最长等待时间、最后完成时间,之间用1个空格分隔,行末不能有多余空格。
在第二行中按编号递增顺序输出每个窗口服务了多少名顾客,数字之间用1个空格分隔,行末不能有多余空格。

输入样例:


9
0 20
1 15
1 61
2 10
10 5
10 3
30 18
31 25
31 2
3

输出:


6.2 17 61
5 3 1

代码:




#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=100010;
int vip_id;
int T[N],P[N];
int is_vip[N];
int n;
int g[N]; //记录每一个窗口最后一个人结束的时间
int cnt[N]; //记录每一个窗口服务的人数
int k;    //窗口数量
int now=0;  //记录现在的时刻
int end_time=0; //记录最后完成时间
int maxn_time=0; //记录最长等待时间
int wait[N]; //记录每一个人的等待时间
double aver_time=0;  // 记录平均等待时间
int allwait=0;    //总共等待时间
int main()
{
  cin>>n;
  for(int i=1;i<=n;i++){
    cin>>T[i]>>P[i];
    if(P[i]>60) P[i]=60;
  } 
  priority_queue<PII,vector<PII>,greater<PII> > heap;   //用小根堆来找当前最快结束的窗口
  // first存窗口结束的时刻,second存窗口的编号
  cin>>k;
  for(int i=0;i<k;i++) heap.push({0,i});  //每一个窗口都是空的
  for(int ii=1;ii<=n;ii++)
  {
    int t=T[ii],p=P[ii]; //第ii个人进来的时间为现在的时间
    now=max(now,t);  
    priority_queue<PII,vector<PII>,greater<PII> > heap2; //中间变量,存储数据
    auto ts=heap.top();
     int ver=ts.second;
    if(ts.first>=now)   //如果当前没有一个窗口有空余,则当前这个人必须得等最快的一个窗口结束
    {
      wait[ii]+=(ts.first-t);  //等待时间
      now=ts.first;        //现在的时间为最快一个窗口结束的时刻
      heap.pop(); //将最快结束的窗口弹出
      heap.push({now+p,ts.second});  //将新进入的人弹入堆
      end_time=max(end_time,now+p);  //最后完成时间
      cnt[ver]++;  //窗口服务人数加一
      continue;
    }
    // 当编号ii的人来时,有空余的窗口
    end_time=max(end_time,now+p);
    while(heap.size())     //更新有多少个窗口有空余位置,存入临时堆heap2中
    {
      auto t=heap.top();
      int vers=t.second;
      if(t.first>now) break;
      heap.pop();
      heap2.push({0,vers});
    }
    while(heap2.size())  //将临时堆中的信息再弹入堆中
    {
      auto t=heap2.top();
      heap2.pop();
      heap.push(t);
    }
    auto ti=heap.top();  //找到编号最小且空余的窗口
    ver=ti.second;
    heap.pop();
    heap.push({now+p,ver});
    cnt[ver]++;
  }
  for(int i=1;i<=n;i++){
    allwait+=wait[i];
    maxn_time=max(maxn_time,wait[i]);
  } 
  aver_time=allwait*1.0/n;
  printf("%.1f %d %d\n",aver_time,maxn_time,end_time);
  for(int i=0;i<k;i++) cout<<cnt[i]<<" \n"[i==k-1];
  return 0;
}
  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值