1017 Queueing at Bank (25分)(优先级队列)

1017 Queueing at Bank (25分)

Suppose a bank has K windows open for service. There is a yellow line in front of the windows which devides the waiting area into two parts. All the customers have to wait in line behind the yellow line, until it is his/her turn to be served and there is a window available. It is assumed that no window can be occupied by a single customer for more than 1 hour.
Now given the arriving time T and the processing time P of each customer, you are supposed to tell the average waiting time of all the customers.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 numbers: N (≤10^​4​​ ) - the total number of customers, and K (≤100) - the number of windows. Then N lines follow, each contains 2 times: HH:MM:SS - the arriving time and P - the processing time in minutes of a customer. Here HH is in the range [00, 23], MM and SS are both in [00, 59]. It is assumed that no two customers arrives at the same time.
Notice that the bank opens from 08:00 to 17:00. Anyone arrives early will have to wait in line till 08:00, and anyone comes too late (at or after 17:00:01) will not be served nor counted into the average.

Output Specification:

For each test case, print in one line the average waiting time of all the customers, in minutes and accurate up to 1 decimal place.

Sample Input:

7 3
07:55:00 16
17:00:01 2
07:59:59 15
08:01:00 60
08:00:00 30
08:00:02 2
08:03:00 10

Sample Output:

8.2

解题思路:

几个坑:1、优先级队列的比较优先级首先是处理时间,其次处理时间相同时窗口号要小(不要忘记了)2、只要顾客到达时间再营业时间范围内都可以

本题感觉最难的地方就是给顾客在每个服务窗口怎么排队,我一开始想法是从所有窗口中选择一个处理时间最短的顾客处理完这个顾客,将这一排所有的窗口的顾客的处理时间减去ta的处理时间,进入一个顾客,然后再反复。。。太复杂容易出错。

其实不需要一个个到窗口入队,可以直接全部入队后,再对各个窗口分开计算即可。首先k个顾客到k个窗口入队后,第K+1个顾客一定是要去K个窗口中选择处理时间最短的一个窗口(因为这个窗口最先完成ta应该补上去),之后第K+2个顾客也是要从当前K个窗口中选择一个总共处理时间最短的时间。。这个反复即可,于是我选择用优先级队列,队头总是处理时间最短的一个窗口,然后将这个窗口的处理时间加上这个顾客的处理时间再入队列,选择一个最短的处理时间窗口。

步骤:

1、将时间化为秒计算(小技巧),建一个数据结构存放顾客【开始时间】与【处理时间】

struct User{
    int _begin,p;

}usr;
 cin>>n>>k;
    int hh,mm,ss,p;
    for(int i=0;i<n;i++){
        scanf("%d:%d:%d %d",&hh,&mm,&ss,&p);
        usr._begin=toSec(hh,mm,ss);
        usr.p=p*60;
        users.push_back(usr);
    }

2、顾客是先来先排队的,因此对【开始时间】递增排序

//比较函数
bool cmp(User a,User b){
    return a._begin<b._begin;
}
sort(users.begin(),users.end(),cmp);

3、根据优先级队列将顾客入队

struct Service{
    int id, sum;
    friend bool operator < (Service a,Service b){
        if(a.sum!=b.sum) return a.sum>b.sum;
        else return a.id>b.id;
    }
};
priority_queue<Service> st;
 for(int i=0;i<k;i++){
        Service s;
        s.id=i;
        s.sum=0;
        st.push(s);
    }//初始化优先级队列
    for(int i=0;i<n;i++){
        Service min_service=st.top();
        st.pop();
        service[min_service.id].push_back(users[i]);
        min_service.sum+=users[i].p;
        st.push(min_service);
    }

4、将每个窗口数组的顾客单独计算其等待时间

 int wait_time=0,index=0;
    int last=toSec(17,0,0);
    for(int i=0;i<k;i++){
        int time=toSec(8,0,0);//上一个顾客处理完成的时间。。默认早上八点
        for(int j=0;j<service[i].size();j++){
            if(service[i][j]._begin<=last){//开始时间再营业时间之内
                if(time>service[i][j]._begin){//当前顾客有等待时间
                    wait_time+=time-service[i][j]._begin;
                    int p=service[i][j].p;
                    time+=p;
                    index++;
                }
                else{//无等待时间
                    time=service[i][j]._begin+service[i][j].p;
                    index++;
                }
            }
        }
    }

AC代码:

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn=100;
int n,k;
struct User{
    int _begin,p;

}usr;
struct Service{
    int id, sum;
    friend bool operator < (Service a,Service b){
        if(a.sum!=b.sum) return a.sum>b.sum;
        else return a.id>b.id;
    }
};
int toSec(int h,int m,int s){
    return h*60*60+m*60+s;
}
vector<User> users;
vector<User> service[maxn];
priority_queue<Service> st;
bool cmp(User a,User b){
    return a._begin<b._begin;
}
int main()
{
    cin>>n>>k;
    int hh,mm,ss,p;
    for(int i=0;i<n;i++){
        scanf("%d:%d:%d %d",&hh,&mm,&ss,&p);
        usr._begin=toSec(hh,mm,ss);
        usr.p=p*60;
        users.push_back(usr);
    }
    sort(users.begin(),users.end(),cmp);
    for(int i=0;i<k;i++){
        Service s;
        s.id=i;
        s.sum=0;
        st.push(s);
    }
    for(int i=0;i<n;i++){
        Service min_service=st.top();
        st.pop();
        service[min_service.id].push_back(users[i]);
        min_service.sum+=users[i].p;
        st.push(min_service);
    }
    int wait_time=0,index=0;
    int last=toSec(17,0,0);
    for(int i=0;i<k;i++){
        int time=toSec(8,0,0);
        for(int j=0;j<service[i].size();j++){
            if(service[i][j]._begin<=last){
                if(time>service[i][j]._begin){
                    wait_time+=time-service[i][j]._begin;
                    int p=service[i][j].p;
                    time+=p;
                    index++;
                }
                else{
                    time=service[i][j]._begin+service[i][j].p;
                    index++;
                }
            }
        }
    }
    printf("%.1f\n",(double)wait_time/(index*60));
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值