PTA 银行排队问题之单队列多窗口服务

假设银行有K个窗口提供服务,窗口前设一条黄线,所有顾客按到达时间在黄线后排成一条长龙。当有窗口空闲时,下一位顾客即去该窗口处理事务。当有多个窗口可选择时,假设顾客总是选择编号最小的窗口。

本题要求输出前来等待服务的N位顾客的平均等待时间、最长等待时间、最后完成时间,并且统计每个窗口服务了多少名顾客。

输入格式:

输入第1行给出正整数N(≤1000),为顾客总人数;随后N行,每行给出一位顾客的到达时间T和事务处理时间P,并且假设输入数据已经按到达时间先后排好了顺序;最后一行给出正整数K(≤10),为开设的营业窗口数。这里假设每位顾客事务被处理的最长时间为60分钟。

输出格式:

在第一行中输出平均等待时间(输出到小数点后1位)、最长等待时间、最后完成时间,之间用1个空格分隔,行末不能有多余空格。

在第二行中按编号递增顺序输出每个窗口服务了多少名顾客,数字之间用1个空格分隔,行末不能有多余空格。

输入样例:

9
0 20
1 15
1 61
2 10
10 5
10 3
30 18
31 25
31 2
3

输出样例:

6.2 17 61
5 3 1

看到这道题目的时候本能的想到应该使用队列,但是其实并没有用到太多队列的性质。

思路:

首先我使用三个数组: window[11]   result[11]   cust[1005]

首先我使用数组 window 来保存每个窗口当前处理人的待处理时间,数组 result 记录每个窗口的累计处理人数,每次增加一个人就自加,数组 cust 负责保存用户信息,变量 front 负责调用队首元素,变量time相当于一个时间轴,它会一直累加,直到 window cust 都为空,此时说明全部处理完毕,time 即为处理的总时间,然后再定义两个变量 MaxWaitTimeAllWaitTime 分别保存最长等待时间和总共的等待时间

 

1、创建用户信息结构

首先我需要创建客户的结构变量,包含 到达时间  需处理时间 等待时间

struct Customer
{
    int arrive;   //到达时间
    int process;  //待处理时间
    int wait;  //等待时间
}cust[1005];

2、数据的输入

然后按照题目要求输入客户的数据,这里要特别注意,每一个顾客的处理时间不超过60分钟,所以对于处理时间大于60分钟的客户,应该把他的时间改成60分钟 (我在一开始的时候认为每个窗口单次最多处理60分钟,时间过了就让客户继续排队,其实不是的,每个人最多允许处理60分钟,超了就不管了,客服只处理60分钟)

for(int i = 0;i < n;i++)
{
	scanf("%d %d",&cust[i].arrive,&cust[i].process);	
	if(cust[i].process > 60)cust[i].process = 60;
}

3、时间轴的累加

这是一个大的循环,每次时间轴 time++,直到所有窗口和队列都为空,此时终止循环

for(time = 0;;time++)
{
    //相关操作
    if(窗口为空 && 队列为空)break;
}

 以下为循环中的详细操作

1、window [ ] 的检查

     每一次时间轴 time 加一,都需要对 window[ ] 的非零元素进行自减

for(int j = 0;j < k;j++)
{
	if(window[j] >= 1)window[j]--;
}

 2、整体等待时间的累加

每一次时间轴 time 加一,此时会对队列中的客户进行检查,如果发现有客户的到达时间比 time 要小,说明此时该客户已经到达了银行,处于等待状态,此时 AllWaitTime ++;

for(int j = front;j < n;j++)
{
	if(cust[j].arrive < time )
	{
		AllWaitTime++;
	}
}

3、客户的入队

遍历窗口,如果发现有窗口为0 并且队列不为空,此时就应该考虑让客户进入新窗口进行处理了,但是要注意,如果此时队首客户的到达时间比time要大,说明该客户还没有到达银行,此时应该终止入队,继续 time 的自加,直到该客户到达了银行

同时在这个过程中,每当一个客户进入到窗口中,那么他的等待时间应该为 time - cust[front].arrive;然后使用 MaxWaitTime 保存最大等待时间即可

随后进行的便是 result[j] 的自加 和 客户入窗口操作

for(int j = 0;j < k;j++)
{
	if(window[j] == 0 && front != n)
    {
		if(cust[front].arrive > time)break; //说明客户还没有到达银行
		cust[front].wait = time - cust[front].arrive; 
		if(MaxWaitTime < cust[front].wait)MaxWaitTime = cust[front].wait;
		result[j]++;
		window[j] = cust[front++].process;
	}
}

4、判断是否已经处理完成

上述过程处理完成后,接下来就是对是否处理完成的判断,设置一个变量t ,然后对 window[ ] 进行遍历累加,如果累加之后 t == 0,说明所有窗口已经处理完毕,此时如果队列也为空,说明处理结束,直接终止循环即可。

int t = 0;
for(int j = 0;j < k;j++)
{
		t += window[j];	
}
if(t == 0 && front == n)break;

5、输出相关内容

这里的输出不做过多赘述

printf("%.1lf %d %d\n",(AllWaitTime * 1.0 / n),MaxWaitTime,time);
for(int i = 0;i < k;i++)
{
	if(i != 0)cout << " ";
	cout << result[i];
}

 

完整代码:

#include <iostream>
#include <cstdio>
using namespace std;

struct Customer
{
	int arrive;	
	int process;
	int wait;
}cust[1005];

int main()
{
	int n,k,time,front = 0,MaxWaitTime = 0,AllWaitTime = 0;
	cin >> n;
	for(int i = 0;i < n;i++)
	{
		scanf("%d %d",&cust[i].arrive,&cust[i].process);	
		if(cust[i].process > 60)cust[i].process = 60;
	}
	int window[11] = {},result[11] = { };
	cin >> k;
	for(time = 0;;time++)
	{
		for(int j = 0;j < k;j++)
		{
			if(window[j] >= 1)window[j]--;
		}
		for(int j = front;j < n;j++)
		{
			if(cust[j].arrive < time )
			{
				AllWaitTime++;
			}
		}
		for(int j = 0;j < k;j++)
		{
			if(window[j] == 0 && front != n)
			{
				if(cust[front].arrive > time)break;
				cust[front].wait = time - cust[front].arrive;
				if(MaxWaitTime < cust[front].wait)MaxWaitTime = cust[front].wait;
				result[j]++;
				window[j] = cust[front++].process;
			}
		}
		int t = 0;
		for(int j = 0;j < k;j++)
		{
			t += window[j];	
		}
		if(t == 0 && front == n)break;
	}
	printf("%.1lf %d %d\n",(AllWaitTime * 1.0 / n),MaxWaitTime,time);
	for(int i = 0;i < k;i++)
	{
		if(i != 0)cout << " ";
		cout << result[i];
	}
	return 0;
}

 

  • 9
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值