银行排队问题之单队列多窗口服务

假设银行有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

Note:这题难点不在于实现,而是理清代码逻辑和细节。一开始我将注意力全放在一个“大时钟”上,去关注整体的情况,但后面发现其中的小部分,只关注整体是很难考虑到的。于是我去看了一下别人的思路,最后总结出来自己的想法。

首先,我们要关注到题目要求输出的几样东西:平均等待时间(输出到小数点后1位)、最长等待时间、最后完成时间,并且统计每个窗口服务了多少名顾客。如果顾客数量很大时,我们在顾客身上统计会很麻烦,所以这些数据,我们要存储到窗口中去。我们让窗口分别记录他们服务顾客的等待时间完成时间,这样在遍历时更加方便,因为样本数据缩小了,我们能更好的理解其中的逻辑顺序。
确定下来后,我们先定义一个用户结构体,由题目提示给他成员变量T和P。排队问题等待问题,自然是队列实现,所以我们用数组来模拟队列,定义一个顾客数组。输完数据后我们就逐个顾客的遍历,当顾客来了之后,总是会选择序号更小的窗口。这就是摆明了说要循环遍历窗口,所以我们内设一个小循环来逐个检查窗口是否能给顾客服务,如果能那就服务好了。不能,就看下一个呗,还不能继续看下一个,直到所有发现所有窗口都是满的。哦豁,那没办法了只能等待了,直到所有顾客都出队列了,我们再统计各项数据然后输出就好了。
这其中就有个问题,就是我们不需要关心每个顾客实际上到达的时间(即与整个时间体系的关系),我们只关心顾客到了之后,他的到达时间和窗口能够提供服务的时间之间的关系。到达时间在完成之间之后,窗口空闲直接服务就好了,到达时间在完成时间之前,窗口有人那就等待。就这么简单的思路,在遍历的同时记录一些特殊数据就好了。

#include 
#include 

typedef struct customer
{ // 定义顾客结构体
    int T, P;
} customer;

int main(void)
{
    customer cus[1010];
    int i, N, K; // 顾客数,窗口数
    int front = 0, rear = 0; // 队首队尾
    int done_time[10] = {0}, done_num[10] = {0}; // 初始化每个窗口的完成时间和服务顾客数
    int wait_time_all = 0, wait_time_max = 0, wait_time_one = 0; // 总的等待时间,最长等待时间,单次等待时间
    int flag, done_time_min, done_time_max = 0, mark; // 是否需要等待的标记,所有窗口中的最小完成时间和最大完成时间,以及相应窗口的序号

    scanf("%d", &N);
    for (rear = 0; rear < N; rear++) // 输入每位顾客的数据,入队过程
    {
        scanf("%d %d", &cus[rear].T, &cus[rear].P);
        if (cus[rear].P > 60)
            cus[rear].P = 60;
    }
    scanf("%d", &K);

    while (front < rear) // 出队过程
    {
        int flag = 0, done_time_min = 99999, mark = 0;
        for (i = 0; i < K; i++) // 遍历窗口
        {
            if (done_time[i] <= cus[front].T) // 队首顾客到达时间在最小完成时间后就不需要等待
            {
                done_time[i] = cus[front].T +cus[front].P; // 新的完成时间为新顾客到达时间+事务处理时间
                done_num[i]++; // 服务顾客数+1
                flag = 1; // 置1表示无需等待
                front ++; // 队首顾客出队
                break; // 跳出循环,处理下一个顾客
            }
            if (done_time_min > done_time[i]) // 如果不满足前一个条件,即完成时间在顾客到达时间之后,顾客需要等待
            { // 记录该窗口的完成时间和窗口序号,k次循环后留下的即是最小完成时间和对应窗口序号
                done_time_min = done_time[i];
                mark = i;
            }
        }
        if (flag == 0) // flag = 0为需要等待
        {
            wait_time_one = done_time_min - cus[front].T; // 最快完成时间减去队首顾客到达时间为单次需要等待的时间
            if (wait_time_max < wait_time_one) // 如果最大等待时间小于单次等待时间就更新
                wait_time_max = wait_time_one;
            wait_time_all += wait_time_one; // 总的等待时间增加
            done_time[mark] = done_time_min + cus[front].P; // 对应窗口完成时间更新
            done_num[mark]++; // 服务顾客数+1
            front++; // 队首顾客出队
        }
    }

    for (i = 0; i < K; i++)
        if (done_time_max 

 自己试着不要看把代码码出来哦,测试样例可以直接复制,加油小伙汁小改改,为了更美好的未来呢~~~

你可能感兴趣的:(随便收录)