PAT甲级1017 银行排队

题目描述

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 (≤104​​ ) - 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.

样例输入:

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

样例输出:

8.2

要求分析

有N个客户来银行办理业务,银行有K个窗口,计算平均每个客户的等待时间。银行8点开门,8点前到的客户也要等到8点才可以办理业务,17点后到的客户不给办理业务。知道每个客户的到达时间和办理业务需要的时长。

知识点

队列

特点先进先出,头文件queue
queue<类型> 队列名字;
队列名字.push(对象); 入队
队列名字.pop(); 出队

排序

头文件algorithm
sort(数组开始,数组结束,比较方法);

第一次提交代码

#include<iostream>
#include<algorithm>
#include<queue>

using namespace std;

const int maxn=11000;
const int maxk=110;

struct custom{
	int hour,min,second,arrivetime,begintime,endtime;
	int P;
	custom():hour(0),min(0),second(0),arrivetime(0),begintime(0),endtime(-1){};	
}cus[maxn];

bool cmp(custom a,custom b){
	return a.arrivetime<b.arrivetime;
}

queue<custom>line[maxk],wait;

int main(){
	int N,K;
	double waittime=0.0;
	cin>>N>>K;
	
	int i;
	for(i=0;i<N;i++){
		scanf("%02d:%02d:%02d %d",&cus[i].hour,&cus[i].min,&cus[i].second,&cus[i].P);
		cus[i].arrivetime=cus[i].hour*60*60+cus[i].min*60+cus[i].second;
	}
	sort(cus,cus+N,cmp);//按到达时间排序 
	for(i=0;i<N;i++){
		if(i<K){//前K个直接服务,不用等待 
			if(cus[i].arrivetime<8*60*60){//8点前到达,需要等待开门 
				waittime+=8*60*60-cus[i].arrivetime;
				cus[i].begintime=8*60*60;
			}
			else
			cus[i].begintime=cus[i].arrivetime;
			cus[i].endtime=cus[i].begintime+cus[i].P*60;
			line[i].push(cus[i]);
		}
		else
		wait.push(cus[i]);//K个之后入等待队伍 
	}
	int nowtime=8*60*60,closetime=17*60*60;//模拟时钟 
	while(nowtime<closetime){//还在营业 
		nowtime++;//每秒刷新检查是否有人的业务完成了 
		for(i=0;i<K;i++){
			if(line[i].empty())//有空窗口
			continue;
			custom head=line[i].front();//取窗口业务完的客户信息
			if(head.endtime<=nowtime||head.endtime>closetime){//当刚好服务完当前客户时或者已经是结束营业时间 
				line[i].pop();//完成业务的客户离开 
				if(!wait.empty()&&wait.front().arrivetime<closetime){//等待队伍非空 
				line[i].push(wait.front());//等待队头去窗口进行业务
				wait.pop();
				}
				else{
					nowtime=closetime;
					break;
				}
				if(line[i].front().arrivetime<head.endtime){//去的时候要等
					line[i].front().begintime=head.endtime;
					line[i].front().endtime=line[i].front().begintime+line[i].front().P*60;
				}
				else{//去的时候有空位
					line[i].front().begintime=line[i].front().arrivetime;
				}
				waittime+=line[i].front().begintime-line[i].front().arrivetime;
			}
		}
		
	}
	while(!wait.empty()){
		N--;
		wait.pop();
	}
	if(N<=0){
		printf("%.1f",0.0);
		return 0;
	}
	printf("%.1f\n",waittime/60/N);
	return 0;
}

提交结果

在这里插入图片描述

错误分析

对于17点刚好踏点来的客人分去了不办理的区域,实际要求是17:00:01开始来的客人才不给办理业务。还有很多细节的地方是多余的和有些数据更新漏了。改进为直接在17:00:01开始来的客人不进入办理队列,把全部业务办理完毕的判断条件改为了营业时间结束或者等待队列为空。不足之处仍有为:每分钟都要刷新询问一遍窗口业务办理是否完成,效率低,但是不想改了,下次一定。

成功通过代码

#include<iostream>
#include<algorithm>
#include<queue>

using namespace std;

const int maxn=11000;
const int maxk=110;

struct custom{
	int hour,min,second,arrivetime,begintime,endtime;
	int P;
	custom():hour(0),min(0),second(0),arrivetime(0),begintime(0),endtime(-1){};
}cus[maxn];

bool cmp(custom a,custom b){
	return a.arrivetime<b.arrivetime;
}

queue<custom>line[maxk],wait;

int main(){
	int N,K;
	double waittime=0.0;
	cin>>N>>K;
	int i;
	for(i=0;i<N;i++){//输入数据 
		scanf("%02d:%02d:%02d %d",&cus[i].hour,&cus[i].min,&cus[i].second,&cus[i].P);
		cus[i].arrivetime=cus[i].hour*60*60+cus[i].min*60+cus[i].second;//计算到达时间,用秒作单位 
	}
	sort(cus,cus+N,cmp);//按到达时间先后排序
	int nowtime=8*60*60,closetime=17*60*60;//模拟时钟
	int countc=N;
	for(i=0;i<N;i++){//N个客户分别入队 
		if(i<K){//前K个直接服务,不用等待
			if(cus[i].arrivetime<closetime){//17点关门前来 
				if(cus[i].arrivetime<8*60*60){//8点前到达,需要等待开门
				waittime+=8*60*60-cus[i].arrivetime;
				cus[i].begintime=8*60*60;
				}
				else
				cus[i].begintime=cus[i].arrivetime;
				cus[i].endtime=cus[i].begintime+cus[i].P*60;//前K个可以直接得到结束时间 
				line[i].push(cus[i]);//前K个客户到窗口
			}
			else
			countc--;
		}
		else{
			if(cus[i].arrivetime<=closetime)//仅在17点前来的可入等待队伍 
			wait.push(cus[i]);
			else
			countc--;	
		}	
	}
	while(nowtime<=closetime||!wait.empty()){//还在营业
		nowtime+=60;//每分钟刷新检查是否有人的业务完成了
		for(i=0;i<K;i++){//逐个窗口检查
			custom head=line[i].front();//取当前在窗口的客户信息
			if(head.endtime<=nowtime){//当刚好服务完当前客户
				line[i].pop();//完成业务的客户离开
				if(!wait.empty()){
				line[i].push(wait.front());//等待队头去窗口进行业务
				wait.pop();
				}
				else{//所有客户均办理业务完成了,退出循环 
					nowtime=closetime+1;
					break;
				}
				if(line[i].front().arrivetime<head.endtime)//去的时候要等
					line[i].front().begintime=head.endtime;
				else//去的时候有空位
					line[i].front().begintime=line[i].front().arrivetime;
				line[i].front().endtime=line[i].front().begintime+line[i].front().P*60;
				waittime+=line[i].front().begintime-line[i].front().arrivetime;
				}	
		}	
	}
	if(N<=0||countc<=0){
		printf("%.1f",0.0);
		return 0;
	}
	printf("%.1lf",waittime/(60.0*countc));
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值