1017. Queueing at Bank (25)

本文详细解析了银行服务排队等待时间计算的问题,包括输入输出规范、算法实现及案例分析,提供了有效的解决思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://www.patest.cn/contests/pat-a-practise/1017

题目:



时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

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 (<=10000) - 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

分析:

和1014(http://blog.youkuaiyun.com/apie_czx/article/details/45537627)题目很相近的题意,不过有区别就是这里的顾客来的时间是随机的。而且在能否得到服务这一点上也是不同的,1014中是即使你在队伍当中,但是如果你在指定时间内(17:00)之前没有 得到服务,那么也是Sorry,而本题中只要你排进了队伍,那么即使超过了五点,也是顺延计算你的时间。

注意点:

最初我还是用时间作为循环变量来进行,但是这样做就不能计算超过17:00的剩余队伍的人的等待时间(因为你无法计算队伍中的人要多久,所以不能设定一个结束时间)

正确的做法应该是把时间循环结束到五点,然后计算队伍中剩下的人。

案例分析:

7个顾客,3个队伍

对顾客的时间排序,

顾客服务时间开始时间等待时间
07:55:001608:00:0000:05:00
07:59:591508:00:0000:00:01
08:00:003008:00:0000:00:00
08:00:02208:15:0000:14:58
08:01:006008:16:0000:15:00
08:03:001008:17:0000:14:00
17:00:012Sorry

总等待时间为00:48:59,6个人,平均等待时间为8.2分钟


AC代码:

#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
struct Time{
 int hour;
 int minute;
 int second;
};//时间结构体
int turn2sec(Time T){
 return T.hour * 60 * 60 + T.minute * 60 + T.second;
}//把时间化为秒
struct Customer{
 int s_time;
 int server_time;
 bool operator < (const Customer &A)const{
  return s_time < A.s_time;
 }//顾客结构体,以及比较函数,按到达的先后
}buf[10002];
int ans[10002];//存储各个顾客的等待时间
int queue[102];//队伍,存储顾客编号
int main(void){
 //freopen("F://Temp/input.txt", "r", stdin);
 int N, K;
 while (scanf("%d%d", &N, &K) != EOF){
  Time tmp;
  for(int i = 0; i < N; i ++){
   scanf("%d:%d:%d", &tmp.hour, &tmp.minute, &tmp.second);
   buf[i].s_time = turn2sec(tmp);
   int server;
   scanf("%d", &server);
   buf[i].server_time = server * 60;
  }
  sort(buf, buf + N);
  for (int i = 0; i < K; i++){
   queue[i] = -1;
  }
  for (int i = 0; i < N; i++){
   ans[i] = -1;
  }//初始化
  int count = 0;
  for (int t = 28800; t <= 864000 && buf[count].s_time <= 61200; t++){//为了应对五点前有顾客开始服务,但是结束的时间超过五点,所以这里的t设置的很大
   for (int i = 0; i < K; i++){
    if (queue[i] != -1){
     int tmp = queue[i];
     if ((buf[tmp].s_time + ans[tmp] + buf[tmp].server_time) == t){//如果到达时间+等待时间(即开始时间)+服务时间==当前时间,则出对
      queue[i] = -1;
     }
    }
   }
   for (int i = 0; i < K; i++){
    if (queue[i] == -1 && t >= buf[count].s_time){
      queue[i] = count;//如果队伍有空,并且当前时间大于顾客的到达时间,则入队
      ans[count] = t - buf[count].s_time;//并计算等待时间
      count++;
    }
   }
  }
  int sum = 0;
  int i;
  for (i = 0; i < N; i++){
   if (ans[i] == -1)break;
   else{
    sum += ans[i];
   }
  }
  if (i == 0)printf("0/n");
  else printf("%.1f\n", (double)sum / i / 60);
 }
 return 0;
}


其实更好的办法的用窗口来,王道的代码如下:

#include <stdio.h>
 #include <string.h>
 #include <algorithm>
 using namespace std;
 
 int N,K,wait_time=0;
 struct Customer
 {
     int arrive_time;
     int need_time;
 };
 
 struct Customer customer[10002];
 
 struct Windows
 {
     int next_available_time;
 };//特别得,窗口结构体,里面是当前顾客的结束时间,也就是窗口下一次空闲的时间
 
 struct Windows windows[102];
 
 bool cmp(struct Customer a,struct Customer b)
 {
     return a.arrive_time<b.arrive_time;
 }
 
 int find_available_windows(int arrive_time)
 {
     int i;
     for(i=0;i<K;i++) {
         if(windows[i].next_available_time<=arrive_time) {
             return i;
         }
     }
     return -1;
 }//找到空闲的窗口
 
 int find_earliest_window()
 {
     int i;
     int e=0;
     for(i=1;i<K;i++) {
         if(windows[i].next_available_time<windows[e].next_available_time) {
             e=i;
         }
     }
     return e;
 }//找到最早的空闲窗口
 
 int main()
 {
     scanf("%d%d",&N,&K);
     int i;
     char arrive_time[20];
     int need_time;
     for(i=0;i<K;i++)
         windows[i].next_available_time=3600*8;//都先初始化为8点
     int len=0;
     for(i=0;i<N;i++) {
         int h,m,s;
         scanf("%s%d",arrive_time,&need_time);
         if(strcmp(arrive_time,"17:00:00")>0)
             continue;
         
         sscanf(arrive_time,"%d:%d:%d",&h,&m,&s);
         if(h<8)
             wait_time+=8*3600-(3600*h+60*m+s);//把所有八点前的顾客到八点的时间都累计,当作都是八点到的
         customer[len].arrive_time=3600*h+60*m+s;
         customer[len++].need_time=need_time*60;
     }
     N=len;
 
     sort(customer,customer+N,cmp);
 
     for(i=0;i<N;i++) {
         int w=find_available_windows(customer[i].arrive_time);
         if(w>=0) {//找到空闲窗口
         //    windows[w].next_available_time=customer[i].arrive_time+customer[i].need_time;
             if(customer[i].arrive_time<8*3600) {
                 windows[w].next_available_time=8*3600+customer[i].need_time;
             } else {
                 windows[w].next_available_time=customer[i].arrive_time+customer[i].need_time;
             }
         } else { //找不到空闲窗口
             w=find_earliest_window();
         /*    wait_time+=windows[w].next_available_time-customer[i].arrive_time;
         *    windows[w].next_available_time=(windows[w].next_available_time-customer[i].arrive_time)+customer[i].need_time;
         */
             if(customer[i].arrive_time<8*3600) {//如果到得早 窗口的下个可用时间等于当前下个可用时间加新来顾客所需要服务时间
                 wait_time+=windows[w].next_available_time-8*3600;
                 windows[w].next_available_time=windows[w].next_available_time+customer[i].need_time;
             } else {
                 wait_time+=windows[w].next_available_time-customer[i].arrive_time;
                 windows[w].next_available_time=windows[w].next_available_time+customer[i].need_time;
             }                
 
         }
     }
 
     printf("%.1f\n",1.0*wait_time/60.0/N);
 }
这里可以看到,王道的代码中是直接找出下一个可用的时间点,然后累加到等待时间总和中,这样它的时间是跳着来的,肯定要比按时间一秒一秒增加得要快得多。

——Apie陈小旭

### 银行排队问题的Python实现 银行排队问题是典型的并行处理和任务分配场景,可以通过ZeroMQ框架中的Ventilator-Worker-Sink模型来解决[^1]。以下是基于该模型的一个简单Python实现: #### ZeroMQ Ventilator 实现 Ventilator负责生成任务并将它们发送给Workers。 ```python import zmq import time context = zmq.Context() # Socket to send tasks to workers sender = context.socket(zmq.PUSH) sender.bind("tcp://*:5557") print("Press Enter when the workers are ready...") _ = input() print("Sending tasks to workers...") # Send out tasks total_msec = 0 for task_nbr in range(100): workload = int((task_nbr * task_nbr) % 100 + 1) # Some random work load total_msec += workload sender.send_string(str(workload)) print(f"Total expected cost: {total_msec} msec") time.sleep(1) # Give 0MQ time to deliver ``` #### ZeroMQ Worker 实现 Worker接收来自Ventilator的任务并执行计算后将结果返回给Sink。 ```python import zmq import sys import time context = zmq.Context() # Socket to receive messages on receiver = context.socket(zmq.PULL) receiver.connect("tcp://localhost:5557") # Socket to send messages to sender = context.socket(zmq.PUSH) sender.connect("tcp://localhost:5558") while True: s = receiver.recv_string() print(f"Received request: {s}") # Do some 'work' time.sleep(int(s) / 10) # Send results to sink sender.send(b'') ``` #### ZeroMQ Sink 实现 Sink收集所有Worker的结果,并统计完成时间。 ```python import zmq import time context = zmq.Context() # Socket to collect worker responses receiver = context.socket(zmq.PULL) receiver.bind("tcp://*:5558") # Wait for start of batch s = receiver.recv() # Start our clock now tstart = time.time() # Process 100 confirmations for task_nbr in range(100): s = receiver.recv() if task_nbr % 10 == 0: sys.stdout.write(':') else: sys.stdout.write('.') sys.stdout.flush() # Calculate and report duration of batch tend = time.time() print(f"\nTotal elapsed time: {(tend-tstart)*1000} msec") ``` 上述代码展示了如何通过ZeroMQ构建一个简单的分布式任务管理系统[^2]。对于银行排队问题,可以将其视为多个客户作为任务被分配到不同的柜员(即Worker),而最终的结果由Sink汇总。 此外,在高并发环境下,还需要注意内存管理和I/O性能优化[^3]。建议使用缓存机制减少磁盘操作频率,并利用消息队列实现各模块间的异步通信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值