• Waiting in Line【PAT 1014题】银行柜台业务办理逻辑


    题目链接:http://pat.zju.edu.cn/contests/pat-practise/1014

    题目一如既往的英文题,内容一大堆其实就是在说一句话:模拟出银行柜台业务办理逻辑,求出指定的顾客业务办理完成的预计时间。这道题之所以写下来,实际上是借此对操作系统的一些知识进行回顾,进程管理时的队列管理和这道题如出一辙,以前都是在书上看看,纸上谈兵,今天才借此题实际的操作了一下。

    先说说这道题的梗概:银行里有n个柜台窗口,每个窗口最多能同时容纳m个顾客排队,多余的呢,随便站在大厅里,只要别蹭到黄线内即可,每个顾客有一个业务处理时间预期值,每当n个窗口的队列不是全满时,即可让黄线外的顾客入队,入队的规则是总是插入到当前队列长度最短的窗口中,如果有多个队列最短,则插入到窗口编号最小的窗口中,银行从早上8:00开始,下午5:00关门,求出指定的顾客业务处理完成时间。

    这道题有一些需要注意的地方:

    1. 如果某一顾客此时刚好业务处理完成,则将其踢出队列,如果他后面有人,则立即更新这个客户的开始服务时间(starttime),如果他后面没有人,则从黄线外拉一个客户入队,并立即更新其starttime,注意是立即,而不是下一分钟。

    2.银行是17:00关门,如果客户A是17:00前接收到了服务,则即使过了17:00,客户A依然可以完成业务处理,而且要输出他的完成时间,不能sorry,而如果客户A在17:00整或以后,则不好意思,sorry

    3.窗口的队列做成循环队列,处理时会带来很大方便

      1 #include <stdio.h>
    2 #include <stdlib.h>
    3
    4 typedef struct
    5 {
    6 int processtime;//该顾客需要花费的时间
    7 int starttime;//该顾客开始处理的时间,8:00认为是0
    8 //以上两个时间相加就可算出该客户业务处理结束的时间,省一个变量
    9 }customer;
    10
    11 typedef struct
    12 {
    13 int id;//该窗口编号
    14 int length;//该窗口当前排队长度,其实也是que的队尾指针
    15 int que[12];//记录顾客的编号,其实就是个指针
    16 int start;
    17 int end;//que需要做成循环队列
    18 }window;
    19
    20 window *wd;
    21 int n, m;
    22
    23 int findWindow()//寻找队列长度最短且编号最小的窗口编号,返回该编号,都满了返回-1
    24 {
    25 int minlen, minpos;
    26 int i;
    27 minlen = wd[0].length;
    28 minpos = 0;
    29 for(i = 1; i < n; i ++)
    30 {
    31 if(wd[i].length < minlen)
    32 {
    33 minlen = wd[i].length;
    34 minpos = i;
    35 }
    36 }
    37 if(minlen >= m)//窗口都满了
    38 {
    39 return -1;
    40 }
    41 else
    42 {
    43 return minpos;
    44 }
    45 }
    46
    47 int allComplete()//所有窗口的所有顾客业务都处理完了吗
    48 {
    49 int i;
    50 for(i = 0; i < n; i ++)
    51 {
    52 if(wd[i].length != 0)
    53 {
    54 return 0;
    55 }
    56 }
    57 return 1;
    58 }
    59
    60 void calculate(customer cus)//将一个顾客的信息导入,输出业务处理结束时间
    61 //PS:17:00前开始的交易都可以不sorry,只有17:00及以后开始的交易才输出sorry
    62 {
    63 int res;
    64 res = cus.processtime + cus.starttime;
    65 int hh,mm;
    66 if(cus.starttime >= 540)
    67 {
    68 printf("Sorry\n");
    69 }
    70 else
    71 {
    72 hh = 8 + res / 60;
    73 mm = res % 60;
    74 printf("%02d:%02d\n", hh, mm);
    75 }
    76 }
    77
    78 int main()
    79 {
    80 int k, q;
    81 int i,j;
    82 customer *ct;//所有顾客队列
    83 int pos;//当前顾客队列站在黄线外面的第一个人,其实就是队列头
    84 int *question;
    85
    86 int time;//时间,每加一分钟检查一下各个窗口
    87 int min;//记录最短队列的窗口编号
    88 int temp;
    89
    90 while(scanf("%d %d %d %d", &n, &m, &k, &q) != EOF)
    91 {
    92 ct = (customer *)malloc((k + 1) * sizeof(customer));
    93 for(i = 1; i <= k; i ++)
    94 {
    95 scanf("%d", &ct[i].processtime);
    96 ct[i].starttime = -1;//表示这个客户还没有接收到服务
    97 }
    98 question = (int *)malloc(q * sizeof(int));
    99 for(i = 0; i < q; i ++)
    100 {
    101 scanf("%d", &question[i]);
    102 }
    103 wd = (window *)malloc(n * sizeof(window));
    104 pos = 1;//顾客编号从1开始,队列0号位不用
    105 for(i = 0; i < n; i ++)
    106 {
    107 wd[i].id = i;
    108 wd[i].length = 0;
    109 wd[i].start = 0;
    110 wd[i].end = 0;
    111 }//初始化windows,bank刚开始上班
    112 time = -1;
    113
    114 /*PS: 处理完一个用户后,下一个用户如果为空,则需立即入队,且立即更新starttime,如果不空,则立即更新starttime*/
    115 while(pos <= k || !allComplete())
    116 {
    117 //先把每个窗口都入满
    118 min = findWindow();
    119 while(min != -1)
    120 {
    121 if(pos > k)//顾客队列都已经站在黄线里等待了,窗口依然没有入满,此时直接break
    122 {
    123 break;
    124 }
    125 wd[min].que[wd[min].end] = pos;
    126 pos ++;
    127 wd[min].length ++;
    128 wd[min].end = (wd[min].end + 1) % 12;
    129 if(wd[min].length == 1)//即该次入队的客户正好可以开始处理业务
    130 {
    131 if(time == -1)//-1表示银行刚开门,更新时间为0
    132 {
    133 ct[wd[min].que[wd[min].start]].starttime = 0;
    134 }
    135 else
    136 {
    137 ct[wd[min].que[wd[min].start]].starttime = time;
    138 }
    139 }
    140 min = findWindow();
    141 }
    142 time ++;//时间在这里滴答滴答,主要是为了前后两个处理可以在同一time下连接起来
    143 //开始轮询处理每个窗口的第一个客户的业务
    144 for(i = 0; i < n; i ++)
    145 {
    146 if(wd[i].length > 0)//该窗口必须得有客户等待,否则会异常
    147 {
    148 temp = wd[i].que[wd[i].start];
    149 if(ct[temp].starttime == -1)//该客户刚排到,使starttime有意义
    150 {
    151 ct[temp].starttime = time;
    152 continue;//该窗口这个time下不需要再管,处理下一个
    153 }
    154 else if(time == ct[temp].starttime + ct[temp].processtime)//客户的业务此时刚好处理完,需要出列
    155 {
    156 wd[i].length --;
    157 wd[i].start = (wd[i].start + 1) % 12;
    158 if(wd[i].length > 0)
    159 {
    160 ct[wd[i].que[wd[i].start]].starttime = time;
    161 continue;
    162 }
    163 //后面还有客户在等待,则立即更新第一个客户的starttime,
    164 //如果没有,则入队的更新交给上面的入队处理
    165 }
    166 }
    167 }
    168 }//保证每个客户都能处理完成业务,而不考虑17:00限制
    169 for(i = 0; i < q; i ++)
    170 {
    171 calculate(ct[question[i]]);
    172 }
    173 }
    174 return 0;
    175 }



  • 相关阅读:
    洛谷 P2607 [ZJOI2008]骑士(基环树、树形dp)
    洛谷 P1453 城市环路(基环树,树形dp)
    基环树学习笔记 & CF711D Directed Roads
    centos7 系统安全加固方案
    来自后端的突袭? --开包即食的教程带你浅尝最新开源的C# Web引擎 Blazor
    作为一个C#程序员, 你应该上手Kotlin
    python中类和self讲解
    Mysql 存储引擎中InnoDB与Myisam的主要区别
    Apache和Nginx的区别
    PHP超全局变量
  • 原文地址:https://www.cnblogs.com/Rafy/p/2406537.html
Copyright © 2020-2023  润新知