优先队列+流程模拟 1017 Queueing at Bank (25分)

1017 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 (≤10
​4
​​ ) - 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

解题
给定N个人和K个窗口,计算出每个人的平均等待时间;

排队规则
按到达时间排序,先到的先处理,保证队列中有K个人;
优先队列按结束时间排序,结束时间早的先出队,然后后面到达时间最早的入队;

1.客户结构
到达时间,处理时间,等待时间,结束时间,开始时间;
都以秒计时比较容易处理;

struct Cus{  
	int time;        //s 到达时间 
	int protime;    //minute    处理时间 
	int waitime;   //s      等待时间 
	int endtime;    //s      结束时间 
	int starttime;    //s    开始时间 
	
	bool operator < (const Cus &t) const{
		return endtime>t.endtime;
	}
};
Cus cus[MAXN];

重构小于号,为优先队列做准备;(优先队列小于号重构与sort相反,后面的<前面的);

2.排序函数

//按时间排序
bool compare(Cus a, Cus b)
{
	return a.time<b.time;
 } 

3.输入函数,得到每个客户的到达时间,处理时间;

int N,K;
void input()
{
	int hour,minute,second;
	cin>>N>>K;
	for(int i=0;i<N;i++)
	{
		scanf("%d:%d:%d %d",&hour,&minute,&second,&cus[i].protime);
		cus[i].time=hour*60*60+minute*60+second;
		cus[i].protime=min(cus[i].protime,60);
		//8点8点之后 
	}
}

4.计算函数
先入队k个元素(若K>N),分类讨论,若客户到达时间早于8点,等待到8点;若客户到达时间晚于8点,等待时间为0; 更新前K个客户的等待时间,开始时间,结束时间,并记录5点之前到达的客户总数;

接着出队头部客户,判断客户的到达时间是否早于5点,若晚于5点则跳出循环;
max(出队客户的结束时间,待入队客户的到达时间)为待入队客户的开始时间,加上处理时间,即为结束时间,更新总等待时间,记录的人数‘;

priority_queue<Cus> q;

void calculate()
{	
	double sumtime=0;   //s
	sort(cus,cus+N,compare);
	
	int i=0;
	int cnt=0;
	for(i=0;i<K&&i<N;i++)
	{
		if(cus[i].time<8*60*60) {
			cus[i].waitime=8*60*60-cus[i].time;
			cus[i].starttime=8*60*60;
			cus[i].endtime=8*60*60+cus[i].protime*60; //s
			sumtime+=cus[i].waitime;
		}
		else 
		{
			cus[i].waitime=0;
			cus[i].starttime=cus[i].time;
			cus[i].endtime=cus[i].starttime+cus[i].protime*60;
		}
		q.push(cus[i]);
		cnt++;
	}
	Cus tmp;
	
	while(i<N)
	{
		tmp=q.top();
		q.pop();
		cus[i].starttime=max(cus[i].time,tmp.endtime);
		if(cus[i].time>17*60*60) break;		//超过5点,不算了 
		cus[i].waitime=cus[i].starttime-cus[i].time;
		cus[i].endtime=cus[i].starttime+cus[i].protime*60;
		q.push(cus[i]);
		cnt++;
		sumtime+=cus[i].waitime;
		i++;
		}
	printf("%.1f",sumtime/(60*cnt));
}

最后计算平均等待时间,就是总等待时间/5点前到达的客户人数,单位为minute;

易错点
五点前到达的客户要统计等待时间,五点后到达的客户不统计等待时间!(并非五点后开始的不统计,若五点前到达,五点后开始,依旧需要统计其等待时间);

完整代码

#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;

const int MAXN = 10001;
const int MAXK = 101;

struct Cus{  
	int time;        //s 到达时间 
	int protime;    //minute    处理时间 
	int waitime;   //s      等待时间 
	int endtime;    //s      结束时间 
	int starttime;    //s    开始时间 
	
	bool operator < (const Cus &t) const{
		return endtime>t.endtime;
	}
};
Cus cus[MAXN];
//按时间排序
bool compare(Cus a, Cus b)
{
	return a.time<b.time;
 } 
 
int N,K;
void input()
{
	int hour,minute,second;
	cin>>N>>K;
	for(int i=0;i<N;i++)
	{
		scanf("%d:%d:%d %d",&hour,&minute,&second,&cus[i].protime);
		cus[i].time=hour*60*60+minute*60+second;
		cus[i].protime=min(cus[i].protime,60);
		//8点8点之后 
	}
}

priority_queue<Cus> q;

void calculate()
{	
	double sumtime=0;   //s
	sort(cus,cus+N,compare);
	
	int i=0;
	int cnt=0;
	for(i=0;i<K&&i<N;i++)
	{
		if(cus[i].time<8*60*60) {
			cus[i].waitime=8*60*60-cus[i].time;
			cus[i].starttime=8*60*60;
			cus[i].endtime=8*60*60+cus[i].protime*60; //s
			sumtime+=cus[i].waitime;
		}
		else 
		{
			cus[i].waitime=0;
			cus[i].starttime=cus[i].time;
			cus[i].endtime=cus[i].starttime+cus[i].protime*60;
		}
		q.push(cus[i]);
		cnt++;
	}
	Cus tmp;
	
	while(i<N)
	{
		tmp=q.top();
		q.pop();
		cus[i].starttime=max(cus[i].time,tmp.endtime);
		if(cus[i].time>17*60*60) break;		//超过5点,不算了 
		cus[i].waitime=cus[i].starttime-cus[i].time;
		cus[i].endtime=cus[i].starttime+cus[i].protime*60;
		q.push(cus[i]);
		cnt++;
		sumtime+=cus[i].waitime;
		i++;
		}
	printf("%.1f",sumtime/(60*cnt));
}

int main()
{
	input();
	calculate();
}

总结
优先队列(最小堆)有效解决每次需要得到队列中最小值的问题,无需遍历时间+遍历数组内的客户,有效减少时间复杂度;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值