PAT甲级(Advanced Level) Practice 1017 Queueing at Bank

原题

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

 题目翻译

假设一家银行开设了 K 个服务窗口。窗口前有一条黄线,将等候区分成两部分。所有客户都必须在黄线后面排队等候,直到轮到他/她,并且有一个窗口空出来。假设任何一个窗口都不能被一个顾客占用超过 1 小时。

现在,给定每位顾客的到达时间 T 和处理时间 P,你应该知道所有顾客的平均等待时间。

输入规范:

每个输入文件包含一个测试用例。每个案例的第一行包含 2 个数字: N (≤10^4) - 顾客总数,K (≤100) - 窗口数。然后是 N 行,每行包含 2 个时间: HH:MM:SS--到达时间,P--以分钟为单位的客户处理时间。这里 HH 的范围是 [00, 23],MM 和 SS 的范围都是 [00, 59]。假设没有两个客户同时到达。

请注意,银行营业时间为 08:00 至 17:00。任何提前到达的客户都必须排队等候至 08:00,而任何太晚到达的客户(17:00:01 或之后)都不会得到服务,也不会计入平均值。

输出说明:

针对每个测试用例,在一行中打印所有顾客的平均等候时间,以分钟为单位,精确到小数点后 1 位。

解题思路

本题和1014 Waiting in Line比较像,区别是本题一个窗口只能站一个人而1014是很多人同时排在一个窗口。因此本题可以不用队列来记录窗口状态,只用记录每个顾客结束办理的时间即可。

这道题有一个公式:等待时间 = 上一个顾客结束时间 - 下一个顾客来的时间。得出这个这道题就非常简单了。

代码(c++)

#include <bits/stdc++.h>

using namespace std;

const int N = 10010, K = 110;

struct customer {
    int atime, spend, wait;                     // atime = arrive_time到达时间
 
    bool operator < (const customer &c) const{
        return atime < c.atime;                 // 按到达时间从小到大排序
    }
}cus[N];

int n, k;
int q[K], st[K];                                // q记录上一用户结束时间,st记录现在柜台前的用户

int main(){
    scanf("%d%d", &n, &k);
    int cnt = n;
    for(int i = 1; i <= n; i++) {
        int hh, mm, ss;
        scanf("%d:%d:%d %d", &hh, &mm, &ss, &cus[i].spend);
        if(cus[i].spend > 60) cus[i].spend = 3600;   // 将所有人的到达时间换成秒的形式,最多不超过60*60=3600
        else cus[i].spend *= 60;
        cus[i].atime = hh * 3600 + mm * 60 + ss;
        if(cus[i].atime > 61200) cnt--;              // 如果来的时间超过17*60*60=61200,不计入
    }
    
    for(int i = 1; i <= k; i++) q[i] = 28800;
    sort(cus + 1, cus + n + 1);
    
    
    int i = 1;
    while(i <= cnt) {
        bool f = false;                                     // 有没有队伍是空的
        for(int j = 1; j <= k; j++) {
            if(!st[j]) {                                    // 空队伍,把顾客放入
                st[j] = i;                                    
                cus[i].wait = max(0, q[j] - cus[i].atime);
                if(cus[i].wait == 0) q[j] = cus[i].atime;
                f = true;
                i++;
                break;
            }
        }
        
        if(!f){                                             // 没有,找出最快结束的队伍
            int minj, mintime = 100000;
            for(int j = 1; j <= k; j++) {  
                if(cus[st[j]].spend + q[j] < mintime) {
                    mintime = cus[st[j]].spend + q[j];
                    minj = j;
                }
            }
            q[minj] += cus[st[minj]].spend;                 // 记录顾客结束时间
            st[minj] = 0;                                   // 没顾客,st=0
        }
    }
    
    int sum = 0;
    for(int i = 1; i <= cnt; i++) sum += cus[i].wait;
    printf("%.1lf", sum / 60.0 / cnt);
    
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值