PAT1017. Queueing at Bank

试题请参见: http://pat.zju.edu.cn/contests/pat-a-practise/1016

题目概述

假设有N个客户在K个窗口等待服务。 每个窗口可以容纳一个人, 因此其他客户需要进行等待. 当某个客户服务完成后, 下一个客户可以进入该窗口并被服务. 我们假设没有窗口会被占用1小时以上.

现在我们给出每个客户的到达时间T和服务该客户所需要的时间P, 请计算所有客户的平均等待时间.

输入

每个输入文件包含一个测试用例. 每个测试用例, 第一行包含两个整数N( <= 1000)和K( <= 100). 其中N表示客户的数量, K表示窗口的数量.
接下来的N行, 包含两个时间: HH:MM:SS, 表示客户的到达时间; P, 表示服务该客户所需要的时间(以分钟为单位).
HH的范围是[00, 23], MM和SS的范围是[00, 59]. 我们假设没有两个客户在同一时间到达.

需要说明的是, 银行的营业时间是08:00-17:00. 如果到达的时间早于08:00, 客户需要等待至银行开始营业才能被服务; 如果客户晚于(或恰好在)17:00:01到达银行, 则该客户不会被服务, 因此也无需计算该客户的平均等待时间.

输出

对于每一个测试用例, 请输出客户的平均等待时间, 以分钟为单位, 并精确到一位小数.

解题思路

典型的模拟题, 并且比PAT 1014要简单一点的模拟题.

读入数据时, 自动过滤17:00:00以后到达的客户.

按客户先后到达顺序进行服务,  在客户服务完成后,  更新窗口的服务完成时间.

客户每次选择服务完成时间最短的进行排队(服务).

需要考虑如下情况: 

- 若银行未营业, 则客户需要等待;

(以及在“遇到的问题”中阐述的一些情况)

遇到的问题

若干次WA, 存在如下需要考虑的情况

1. 若所有顾客都在17:00:00以后到达, 则结果为0.0;
2. 若当前所有顾客都已服务完毕, 但是下一位顾客还未到来, 需要窗口需要等待;
3. 若当前客户不需要等待, 则该窗口服务完成时间时为客户到达时间 + 服务时间; 否则, 该窗口服务完成时间为上一个客户完成的时间 + 该客户服务时间.

源代码

#include <iostream>
#include <iomanip>
#include <fstream>
#include <algorithm>
#include <string>
#include <vector>

const std::string BANK_OPEN_TIME = "08:00:00";
const std::string BANK_CLOSE_TIME = "17:00:00";

struct Customer {
    std::string arrivedTime;
    int waitingTime;      // seconds
    int processingTime;   // seconds
    
    Customer() {
        waitingTime = 0;
        processingTime = 0;
    }
};

struct Window {
    int currentTime;      // seconds

    Window() {
        currentTime = 0;
    }
};

int atoi(char timeDigit0, char timeDigit1) {
    return (timeDigit0 - '0') * 10 + (timeDigit1 - '0');
}

int getIntervalBetweenTime(const std::string& startTime, const std::string& endTime) {
    if ( startTime >= endTime ) {
        return 0;
    }

    int startHour = atoi(startTime[0], startTime[1]);
    int startMinute = atoi(startTime[3], startTime[4]);
    int startSecond = atoi(startTime[6], startTime[7]);
    int endHour = atoi(endTime[0], endTime[1]);
    int endMinute = atoi(endTime[3], endTime[4]);
    int endSecond = atoi(endTime[6], endTime[7]);

    int interval = (endHour - startHour) * 3600 + (endMinute - startMinute) * 60
                 + (endSecond - startSecond);
    return interval;
}

int getIntervalBetweenTime(const std::string& startTime, int endTime) {
    int startHour = atoi(startTime[0], startTime[1]);
    int startMinute = atoi(startTime[3], startTime[4]);
    int startSecond = atoi(startTime[6], startTime[7]);
    int interval = endTime - ((startHour - 8) * 3600 + startMinute * 60 + startSecond);


    return (interval > 0 ? interval : 0);
}

int getCustomerCompleteTime(std::string& arrivedTime, int processingTime) {
    if ( arrivedTime < BANK_OPEN_TIME ) {
        arrivedTime = BANK_OPEN_TIME;
    }
    int arrivedHour = atoi(arrivedTime[0], arrivedTime[1]);
    int arrivedMinute = atoi(arrivedTime[3], arrivedTime[4]);
    int arrivedSecond = atoi(arrivedTime[6], arrivedTime[7]);
    int completeTime = (arrivedHour - 8) * 3600 + arrivedMinute * 60 + arrivedSecond + processingTime;

    return completeTime;
}

bool customerCompare(const Customer& customer1, const Customer& customer2) {
    return customer1.arrivedTime < customer2.arrivedTime;
}

int main() {
    // std::ifstream cin;
    // cin.open("input.txt");
    using std::cin;

    int n = 0, k = 0;
    cin >> n >> k;

    std::vector<Customer> customers;
    std::vector<Window> windows(k);

    // Input
    for ( int i = 0; i < n; ++ i ) {
        Customer customer;
        cin >> customer.arrivedTime >> customer.processingTime;
        if ( customer.arrivedTime <= BANK_CLOSE_TIME ) {
            customer.processingTime *= 60;
            customers.push_back(customer);
        }
    }

    // Processing
    std::sort(customers.begin(), customers.end(), customerCompare);
    size_t customerIndex = 0;
    for ( ; customerIndex < k && customerIndex < customers.size(); ++ customerIndex ) {
        Customer& customer = customers[customerIndex];
        Window& window = windows[customerIndex];
        customer.waitingTime = getIntervalBetweenTime(customer.arrivedTime, BANK_OPEN_TIME);
        window.currentTime += getCustomerCompleteTime(customer.arrivedTime, customer.processingTime);
    }

    for ( ; customerIndex < customers.size(); ++ customerIndex ) {
        int firstCompleteWindowIndex = 0, firstCompleteWindowTime = 1 << 30;
        // Search for a window to serve
        for ( size_t i = 0; i < windows.size(); ++ i ) {
            if ( windows[i].currentTime < firstCompleteWindowTime ) {
                firstCompleteWindowTime = windows[i].currentTime;
                firstCompleteWindowIndex = i;
            }
        }
        Customer& customer = customers[customerIndex];
        Window& window = windows[firstCompleteWindowIndex];
        customer.waitingTime = getIntervalBetweenTime(customer.arrivedTime, window.currentTime);
        int completeTime = getCustomerCompleteTime(customer.arrivedTime, customer.processingTime);
        if ( customer.waitingTime == 0 ) {
            window.currentTime = completeTime;
        } else {
            window.currentTime += completeTime;
        }
    }

    // Output
    double averageWaitTime = 0;
    for ( size_t i = 0; i < customers.size(); ++ i ) {
        averageWaitTime += customers[i].waitingTime;
    }
    if ( customers.size() != 0 ) {
        averageWaitTime /= customers.size() * 60;
    }

    std::cout << std::fixed << std::setprecision(1) << averageWaitTime << std::endl;

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值