题目链接: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 }