【PAT甲级】个人做题记录之:1017 Queueing at Bank (25 分)

由于之前审核原创,所以好像相似的题目标题都要进行人工的原创审核,因此试着改一下标题,看能不能让机器审核通过

由于最近在公司实习,所以没法即使更新pat甲级的做题训练,马上九月份就要考试了,也不知道这次训练这么少能考个什么成绩,总之,加油!

1017 Queueing at Bank

题目描述:

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
思路:

本题是一个模拟类型的题目,即使用计算机程序来模拟不同人进入银行处理业务的整个流程,与1014题目有点类似,我们使用队列数组vector<queue<people>> windows来模拟银行的多个窗口,每一个队列存放在该窗口处理业务的人的信息,队列头是正在处理的人的信息。

其中people是自定义的结构体,结构体中包含以下几个参数,此人进入银行的时间be,开始处理业务的时间st,结束业务的时间ed,以及处理业务需要的时间pt

struct people
{
	int be,st,ed;//进入银行时间与开始处理时间,结束时间
	int pt;
};

另外,在这里我记录时间的方式是使用6位数字来记录时间,例如163030代表16:30:30

自己做完以后参照网上各路大神方法,可以只用使用秒数来定位时间,处理起来比较方便

因此定义了两个函数来对这样的时间格式进行处理,如下:

第一个宏用于计算两个时间之间的秒数,第二个内联函数用于计算从a时刻经历b分钟到达的时刻(因为题目给定的处理时间都是分钟,需要计算什么时刻处理结束)

//计算两个时间之间的秒数
#define A_to_B_Time(a,b) (((b)/10000-(a)/10000)*60*60+((b)%10000/100-(a)%10000/100)*60+((b)%100-(a)%100))
//计算从A时间经过B分钟到达的时间
inline int A_time_plus_B(int a,int b)
{
	int plus=a%10000/100+b;
	int time=(a/10000+plus/60)*10000+plus%60*100+a%100;
	return time;
}

于是,在输入初始的所有人的数据的时候,使用下面的方法将所有人的信息存储在一个vector<people> store数组中,同时按照进入的时间的先后顺序bool compare(people a,people b)进行排序,注意同时要记录有多少人是17点以前进入银行的,这些人一定是要处理的【这是部分测试点的坑,对于早于17点进入银行的人,即使等到了17点之后还么轮到他们,一定也要将他们处理完毕】

void input()
{
	scanf("%d %d",&N,&K);
	int h,m,s,p;
	All=0;
	for(int i=0;i<N;i++)
	{
		scanf("%d:%d:%d %d",&h,&m,&s,&p);
		people temp;
		temp.be=h*10000+m*100+s;//进入银行的时间是h:m:s,用6位整数记录
		if(temp.be<=170000)All++;//计算总共有多少人要进行处理
		temp.st=0;
		temp.ed=0;
		temp.pt=p;
		store.push_back(temp);
	}
	windows.resize(K);
	sort(store.begin(),store.end(),compare);
}
bool compare(people a,people b)
{
	return a.be<b.be;
}

之后就是模拟所有窗口的处理过程,首先将早于八点进入的人,放入最开始的每一个窗口前。之后按照时间time从80000开始进行循环,每次增加一秒,直到所有的要求处理的顾客全部处理完毕退出循环。

在每一个时刻,都要对所有的窗口进行检查,如果到达该人的处理时间,将该人弹出,如果队列为空,判断有没有顾客要进行新的业务,有的话,将该人压入队列【注意,每次入队的时候,都要计算其离开时间】

void simulation()
{
	int head=0;//定义头指针
	//首先将早于八点进入的人,放入最开始的每一个窗口前
	for(int i=0;i<K;i++)//开始时刻将早于八点到的顾客放入队列
	{
		if(head<N)
		{
			if(store[head].be<=80000)
			{
				store[head].st=80000;//最初进入队列的人的开始时间是八点
				store[head].ed=A_time_plus_B(store[head].st,store[head].pt);
				windows[i].push(store[head++]);
			}
		}
	}
	for(int time=80000;head<All;time++)//注意循环结束条件不是终止时间小于17点,而是所有能处理的人处理完
	{
	//对于时间进行循环时候的更改规则,60进制
		if(time%100==60)//每过60秒,增加一分钟
			time+=40;
		if(time%10000==6000)//每过60分钟,增加一小时
			time+=4000;
		for(int i=0;i<K;i++)
		{
			if(!windows[i].empty())//如果队列不空
			{
				//队列头的人结束了
				if(windows[i].front().ed==time)
				{
					windows[i].pop();
				}
			}
			if(windows[i].empty())//如果队列空了,看能不能加人
			{
				if(head<N)//还有待处理的人
				{
					if(store[head].be<=time)
					{
						store[head].st=time;
						store[head].ed=A_time_plus_B(store[head].st,store[head].pt);
						windows[i].push(store[head++]);
					}
				}
			}
		}
	}
	return;
}

进行完以上的模拟,每个人的开始处理时间,结束时间都进行了记录,可以计算最终的平均等待时间:

double cal_average()
{
	int number=0;double sum=0;
	for(int i=0;i<N;i++)
	{
		if(store[i].st!=0)
		{
			number++;
			sum+=A_to_B_Time(store[i].be,store[i].st);//计算从进入银行到开始处理业务的时间差
		}
	}
	if(number==0)
		return 0;
	return sum/60.0/number;
}

主函数:

int main()
{
	input();
	simulation();
	printf("%.1f\n", cal_average());
	return 0;
}
代码
//1017 Queueing at Bank
#include<stdio.h>
#include<queue>
#include<vector>
#include<algorithm>

using namespace std;

//计算两个时间之间的秒数
#define A_to_B_Time(a,b) (((b)/10000-(a)/10000)*60*60+((b)%10000/100-(a)%10000/100)*60+((b)%100-(a)%100))
//计算从A时间经过B分钟到达的时间
inline int A_time_plus_B(int a,int b)
{
	int plus=a%10000/100+b;
	int time=(a/10000+plus/60)*10000+plus%60*100+a%100;
	return time;
}

struct people
{
	int be,st,ed;//进入银行时间与开始处理时间,结束时间
	int pt;
};

vector<people> store;
vector<queue<people>> windows;
int N,K;
int All;//存储所有能处理的人的个数

void input();
bool compare(people a,people b);
void simulation();
double cal_average();

int main()
{
	input();
	simulation();
	printf("%.1f\n", cal_average());
	return 0;
}

void input()
{
	scanf("%d %d",&N,&K);
	int h,m,s,p;
	All=0;
	for(int i=0;i<N;i++)
	{
		scanf("%d:%d:%d %d",&h,&m,&s,&p);
		people temp;
		temp.be=h*10000+m*100+s;
		if(temp.be<=170000)All++;//计算总共有多少人要进行处理
		temp.st=0;
		temp.ed=0;
		temp.pt=p;
		store.push_back(temp);
	}
	windows.resize(K);
	sort(store.begin(),store.end(),compare);
}

bool compare(people a,people b)
{
	return a.be<b.be;
}

void simulation()
{
	int head=0;
	for(int i=0;i<K;i++)//开始时刻将早于八点到的顾客放入队列
	{
		if(head<N)
		{
			if(store[head].be<=80000)
			{
				store[head].st=80000;//最初进入队列的人的开始时间是八点
				store[head].ed=A_time_plus_B(store[head].st,store[head].pt);
				windows[i].push(store[head++]);
			}
		}
	}
	for(int time=80000;head<All;time++)//注意循环结束条件不是终止时间小于17点,而是所有能处理的人处理完
	{
		if(time%100==60)
			time+=40;
		if(time%10000==6000)
			time+=4000;
		for(int i=0;i<K;i++)
		{
			if(!windows[i].empty())//如果队列不空
			{
				//队列头的人结束了
				if(windows[i].front().ed==time)
				{
					windows[i].pop();
				}
			}
			if(windows[i].empty())//如果队列空了,看能不能加人
			{
				if(head<N)//还有待处理的人
				{
					if(store[head].be<=time)
					{
						store[head].st=time;
						store[head].ed=A_time_plus_B(store[head].st,store[head].pt);
						windows[i].push(store[head++]);
					}
				}
			}
		}
	}
	return;
}

double cal_average()
{
	int number=0;double sum=0;
	for(int i=0;i<N;i++)
	{
		if(store[i].st!=0)
		{
			number++;
			sum+=A_to_B_Time(store[i].be,store[i].st);
		}
	}
	if(number==0)
		return 0;
	return sum/60.0/number;
}

git仓库:1017 Queueing at Bank

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值