Queueing at Bank (25)

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. Waiting in Line略有不同。那就是,17:00:00以及之前到达的顾客都可以得到服务,结束服务的时间=开始服务的时间+服务时间。而1014里,一到17:00:00所有顾客不管是正在服务的还是未曾服务的,都需要离开;对于在17:00:00之前未曾轮到的顾客(包括正好在17:00:00轮到的顾客)都需要输出sorry。不注意到这一点,此题最后的测试点无法通过

案例分析:

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分钟
大神思路:
在读取客户时就把到达时间大于或等于17:01的客户去掉。设定一个队列,每当一个窗口出现空闲,而且队列里有人,就出队一个人。记录每一个人的到达时间和开始服务的时间、完成服务的时间

赋大神代码:
#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;  
}  
我的思路比较传统
开K个窗口数组,数组内记录的是下一次空闲时间例如某个人08:00:00来的,服务时间为16则他所在的窗口就赋值为08:16:00,当下一个顾客来的时候很容易就算出了等待时间例如下一个顾客8:10:00来的等待时间就是6分钟
这和生活中是一样的,生活中我们去银行,先按照到来的时间摇号排序,然后肯定是只要空出一个窗口,我们就会去那个窗口办理业务,如果每个窗口上显示当前顾客完成业务的时间,你会不会去挑一个最早的去排队呢?我的思路就是这样,每个窗口都有当前顾客办理业务完成时间,将顾客按照先来后到排序,将17:00:01后来的去掉,用循环控制每个顾客,每个顾客选窗口前都先扫一遍每个窗口的时间,选最早完成的,然后去办理业务,更新窗口时间值,就这样,直到所有顾客办理完业务
顾客服务时间开始时间等待时间
07:55:00  ①1608:00:0000:05:00
07:59:59  ②1508:00:0000:00:01
08:00:00  ③3008:00:0000:00:00
08:00:02  ④208:15:0000:14:58
08:01:00  ⑤6008:16:0000:15:00
08:03:00  ⑥1008:17:0000:14:00
17:00:012Sorry

就拿这个例子来说,窗口初始值都为08:00:00,①②③号顾客分别在(1),(2),(3)窗口他们办理业务时窗口值更新为08:16:00    08:15:00
08:30:00很显然④号顾客要选08:15:00结束的那个窗口排队,此时2号窗口更新为08:17:00,而4号顾客等待的时间就是窗口时间-④号到达的时间即08:15:00-08:00:02下面同理
当然如果前面没有顾客办理业务,等待时间就不能用窗口值进行计算。
附上我恐怖的代码
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>  
using namespace std;
string opentime="08:00:00",closetime="17:00:00";
struct customer
{
	string comtime;
	int servetime;	
}c[10001];
vector<string> windows(101,opentime);//窗口
string cal1(string ctmp,int wtmp)//计算开始服务时间+服务时间,例如开始服务时间为08:00:00,服务时间为16min,计算结果返回08:16:00
{
	int ctmin,ltmin,cthour,lthour,flag=0;
	string ltmp=ctmp;
	ctmin=stoi(ctmp.substr(3,2));
	cthour=stoi(ctmp.substr(0,2));
	ltmin=wtmp+ctmin;
	if(ltmin>60)
	{
		ltmin-=60;
		flag=1;
	}
	lthour=cthour+flag;
	ltmin>=10?ltmp.replace(3,2,to_string(ltmin)):ltmp.replace(3,2,'0'+to_string(ltmin));
	lthour>=10?ltmp.replace(0,2,to_string(lthour)):ltmp.replace(0,2,'0'+to_string(lthour));
	return ltmp;
}
int cal2(string t1,string t2)//计算两个时间点的时间差,以秒为单位,例如输入08:00:00与08:01:00,输出就是60秒
{
	int th1=stoi(t1.substr(0,2)),tm1=stoi(t1.substr(3,2)),ts1=stoi(t1.substr(6,2));
	int th2=stoi(t2.substr(0,2)),tm2=stoi(t2.substr(3,2)),ts2=stoi(t2.substr(6,2));
	if(ts2<ts1)
	{
		tm2-=1;
		ts2+=60;
	}
	if(tm2<tm1)
	{
		th2-=1;
		tm2+=60;
	}
	return (th2-th1)*3600+(tm2-tm1)*60+(ts2-ts1);
}
int cmp(customer a,customer b)//sort里用的compare函数
{
	return a.comtime<b.comtime?1:0;
}
int findmin(int k)//找到所有k个窗口中结束时间最早的
{
	int mini=0;
	string min="99:59:59";
	for(int i=0;i<k;i++)
		if(min>windows[i])
		{
			mini=i;
			min=windows[i];
		}
	return mini;
}
int main(){
	int n,k,wtmp,no=0,time=0,notmp=0;
	double avg;
	string ctmp;
	cin>>n>>k;
	for(int i=0;i<n;i++)
	{
		cin>>ctmp>>wtmp;
		if(ctmp<=closetime)
		{
			c[no].comtime=ctmp;
			c[no++].servetime=wtmp;
		}
	}
	sort(c,c+no,cmp);//排序
	for(int i=0;i<n&&c[i].comtime<opentime;i++)//先计算08:00:00前到的,这些人都要等
	{
		time+=cal2(c[i].comtime,opentime);
		c[i].comtime=opentime;
	}
	while(notmp<no)//对每个顾客分别计算等待时间,注意这个顾客前面有空窗口和没有时,time的值和windows的值要分别计算
	{
		int fmin=findmin(k);
		int timetmp=cal2(c[notmp].comtime,windows[fmin]);	
		time+=(timetmp>0?timetmp:0);
		windows[fmin]=cal1(max(windows[fmin],c[notmp].comtime),c[notmp].servetime);
		notmp++;
	}
	avg=(time*1.0)/(60*no);
	printf("%.1lf\n",avg);
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值