1017 Queueing at Bank (25分)

1 题目

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 (≤104​​ ) - 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

2 解析

2.1 题意

求顾客的平均等待时间

2.2 思路

  • 注意点:

    • 超过17:00以后(不包括17:00)到达的顾客,不服务 ;
    • 8:00之前到达的顾客,要等到8:00才开始服务,这一段时间计入等待时间;
    • 关于时间的计算,可以把所有时间化为秒,计算完后,再转换为分钟
    • 服务时间超过一个小时的按一个小时计算;
  • 1 读入并记录顾客到达时间以及服务时间,当顾客到达时间超过营业结束时间时,不记录;同时预处理顾客等待时间,当顾客到达时间早于开始营业时间,顾客等待时间=开始营业时间-顾客到达时间;

  • 2 按照顾客到达时间的先后给顾客排序;

  • 3 设windowsEndTime[i]为第i个窗口结束服务的时间,serveWindows为所有窗口最早结束服务的时间(初始为windowsEndTime[windowsNum]),windowsNum为剩余空闲窗口数;

    • 当剩余空闲窗口大于0时,windowsEndTime[windowsNum]= 顾客到达时间+顾客服务时间(如果顾客到达时间早于开营营业时间,顾客到达时间同开始营业时间替换),同时比较最早的窗口结束时间windowsEndTime[serveWindows];
    • 当剩余空闲窗口等0时,
      • 如果顾客到达时间大于或等于所有窗口最早结束服务的时间,最早结束服务的窗口的结束服务时间更替为windowsEndTime[serveWindows]=顾客到达时间+顾客服务时间;
      • 如果顾客到达时间小于所有窗口最早结束服务的时间,顾客总等价时间 = windowsEndTime[serveWindows] - 顾客到达时间,同时最早结束服务的窗口的结束服务时间更替为windowsEndTime[serveWindows] += 顾客服务时间;
      • 最后寻找所有窗口的最早结束服务时间。
  • 优化:

  • 设windowsEndTime[i]为第i个窗口结束服务的时间,初始值为开始营业时间,serveWindows为所有窗口最早结束服务的窗口编号,windowsEndTime[serveWindows]为所有窗口最早结束服务的时间;

    • 寻找所有窗口最早结束服务的时间;
    • 如果顾客到达时间早于windowsEndTime[serveWindows],顾客总等价时间 = windowsEndTime[serveWindows] - 顾客到达时间 ,windowsEndTime[serveWindows] += 顾客服务时间;
    • 如果顾客到达时间大于或等于windowsEndTime[serveWindows],windowsEndTime[serveWindows] = 顾客到达时间 + 顾客服务时间。

3 参考代码

3.1 未优化

#include <cstdio>
#include <algorithm>
#include <vector>

using std::vector;
using std::sort;

struct Information
{
    int m_comeTime;//客户到达时间
    int m_serveTime;//客户服务时间
    Information(int _a, int _b): m_comeTime(_a), m_serveTime(_b){}
};

vector<Information> customer;//顾客队列
int N, K;
int waitingTime = 0;//总等总等待时间
int windowsEndTime[110];//记录第i号窗口当前服务客服的结束时间

int calTime(int h, int m, int s){
    return h * 3600 + m * 60 + s;
}

bool cmp(Information a, Information b){
    return a.m_comeTime < b.m_comeTime;
}

int main(int argc, char const *argv[])
{
    scanf("%d%d", &N, &K);

    int startTime = calTime(8, 0, 0);//开始营业时间
    int endTime = calTime(17, 0, 0);//结束营业时间
    for (int i = 0; i < N; ++i)
    {
        int h, m, s, tempServerTime;
        scanf("%d:%d:%d %d", &h, &m, &s, &tempServerTime);
        int comeTime = calTime(h,  m , s);//计算顾客到来时间

        if(comeTime > endTime) continue;//到达时间比结束营业时间晚

        //顾客服务时间超过一个小时按一个小时算
        int serveTime = tempServerTime >= 60 ? 3600 : (tempServerTime * 60);
        customer.push_back(Information(comeTime, serveTime));

        //顾客到达时间早营业时间,提前计算顾客等待时间
        if(comeTime < startTime){
            waitingTime += startTime - comeTime;
        }
    }
    //按顾客到达时间的先后排序
    sort(customer.begin(), customer.end(), cmp);

    int windowsNum = K;//剩余空闲窗口数
    int serveWindows = K;//最早结束服务的窗口编号
    for (int i = 0; i < customer.size(); ++i)
    {
        if(windowsNum > 0){

            if(customer[i].m_comeTime < startTime){//来的比开始营业时间早
                windowsEndTime[windowsNum] = startTime + customer[i].m_serveTime;//计算窗口结束时间
            }else{
                windowsEndTime[windowsNum] = customer[i].m_comeTime + customer[i].m_serveTime;
            }

            if(windowsEndTime[windowsNum] < windowsEndTime[serveWindows]){//更新最早结束窗口时间
                serveWindows = windowsNum;
            }
            windowsNum--;
        }else{

            if(windowsEndTime[serveWindows] > customer[i].m_comeTime){//新到顾客来的时间比新空闲窗口开始的时间早
                waitingTime += windowsEndTime[serveWindows] - customer[i].m_comeTime;
                windowsEndTime[serveWindows] += customer[i].m_serveTime;
            }else{
                windowsEndTime[serveWindows] = customer[i].m_comeTime + customer[i].m_serveTime;
            }

            for (int i = 1; i <= K; ++i)//重新寻找最早空闲窗口的开始时间
            {
                if(windowsEndTime[i] < windowsEndTime[serveWindows]){
                    serveWindows = i;
                }
            }

        }

    }

    if(customer.size() == 0){//所有顾客来的时间都比结束营业时间晚
        printf("0.0");
    }else{
        double ans =((1.0 * waitingTime) / 60) / customer.size();
        printf("%.1f\n", ans);
    }

    return 0;
}



3.2 优化

#include <cstdio>
#include <algorithm>
#include <vector>

using std::vector;
using std::sort;

struct Information
{
    int m_comeTime;//客户到达时间
    int m_serveTime;//客户服务时间
    Information(int _a, int _b): m_comeTime(_a), m_serveTime(_b){}
};

vector<Information> customer;//顾客队列
int N, K;
int waitingTime = 0;//总等总等待时间
int windowsEndTime[110];//记录第i号窗口当前服务客服的结束时间

int calTime(int h, int m, int s){
    return h * 3600 + m * 60 + s;
}

bool cmp(Information a, Information b){
    return a.m_comeTime < b.m_comeTime;
}

int main(int argc, char const *argv[])
{
    scanf("%d%d", &N, &K);

    int startTime = calTime(8, 0, 0);//开始营业时间
    int endTime = calTime(17, 0, 0);//结束营业时间
    
    //初始化每个窗口的结束服务时间
    for (int i = 1; i <= K; ++i) {
        windowsEndTime[i] = startTime;
    }

    for (int i = 0; i < N; ++i)
    {
        int h, m, s, tempServerTime;
        scanf("%d:%d:%d %d", &h, &m, &s, &tempServerTime);
        int comeTime = calTime(h,  m , s);//计算顾客到来时间

        if(comeTime > endTime) continue;//到达时间比结束营业时间晚

        //顾客服务时间超过一个小时按一个小时算
        int serveTime = tempServerTime >= 60 ? 3600 : (tempServerTime * 60);
        customer.push_back(Information(comeTime, serveTime));

    }
    //按顾客到达时间的先后排序
    sort(customer.begin(), customer.end(), cmp);

    int serveWindows = 1;
    for (int i = 0; i < customer.size(); ++i) {
        for (int j = 1; j <= K; ++j) {
            if(windowsEndTime[j] < windowsEndTime[serveWindows]){
                serveWindows = j;
            }
        }

        if(customer[i].m_comeTime < windowsEndTime[serveWindows]){
            waitingTime += windowsEndTime[serveWindows] - customer[i].m_comeTime;
            windowsEndTime[serveWindows] += customer[i].m_serveTime;
        }else{
            windowsEndTime[serveWindows] = customer[i].m_comeTime + customer[i].m_serveTime;
        }

    }

    if(customer.size() == 0){//所有顾客来的时间都比结束营业时间晚
        printf("0.0");
    }else{
        double ans =((1.0 * waitingTime) / 60) / customer.size();
        printf("%.1f\n", ans);
    }

    return 0;
}



已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 设计师:繁星蓝雨 返回首页