PAT甲组1017.Queueing at Bank思路与注意点--补充《算法笔记》

A1017

题目链接

个人思路

一开始还想着正儿八经用queue,其实用数组就可以模拟。个人想到了用秒来统一标识时间
个人思路是通过模拟银行一天的营业时间来计算等待时间,在某个时间点对所有窗口进行遍历寻找空闲窗口。时间复杂度为106:(18点-8点) * 3600秒 * 100个窗口(18点:17点客户到达,处理一个小时)

  • 时间等于窗口结束时间便标记为空闲
  • 当前排队的客户使用空闲窗口,更改窗口状态,计算客户等待时间和窗口结束时间

个人思路代码

感觉思路挺对的,不知道哪里出了问题

#include <bits/stdc++.h>
using namespace std;
int N, K;
struct Node{
	int start;//到银行时间用秒表示 
	int d;//处理时间用秒表示 
	Node(){}
	Node(int ss, int dd)
	{
		start = ss;
		d = dd;
	}
}nodes[10005];
struct Window{
	int end;//当前用户的结束时间 
	bool status = true;//true:可用,false:不可用 
	Window(){}
	Window(int e, bool s)
	{
		end = e;
		status = s;
	}
}windows[105];


bool cmp(Node n1, Node n2)
{
	return n1.start < n2.start;
}
//时间点用秒表示(距离00:00:00多少秒) 
int getSecond(int h, int m, int s)
{
	return h * 3600 + m * 60 + s;
}
int main(int argc, char *argv[]) {
	scanf("%d%d", &N, &K);
	int sum = 0, num = 0;//等待时间总秒数sum,总人数num 
	int open = 8 * 3600;//银行开门时间
	int end = 17 * 3600;
	for(int i = 0; i < N; ++i)
	{
		int h, m ,s ,d;
		scanf("%d:%d:%d %d", &h, &m, &s, &d);
		int ss = getSecond(h, m, s);
		int dd = d * 60;
		if(ss > end)//关门来晚了 
			continue;
		nodes[num++] = Node(ss, dd);//有效客户 
	}
	sort(nodes, nodes + num, cmp);
	
	
	int cnt = 0;//记录已经处理的人数
	//开始时间,模拟整个时间 
	int now = open;
	while(cnt < num)
	{
		if(now < nodes[cnt].start)
		{
			now++;
			continue;
		}
		for(int i = 0; i < K; ++i)//寻找有没有可用窗口 
		{
			if(windows[i].end == now)//窗口服务结束
			{
				windows[i].status = true;//标记为可用
			}
			if(windows[i].status == true && cnt < num)//窗口空闲,cnt<num防止出现窗口数大于人数的情况
			{
				windows[i].end = now + nodes[cnt].d;
				windows[i].status = false;
				if(now >= nodes[cnt].start) //如果now小于start,说明是窗口一直有空闲 
					sum += now - nodes[cnt].start;//计算等待时间
				cnt++; 
			}	
		}
		now++;	
	}
	if(cnt == 0 || num == 0)
		printf("0.0");
	else
		printf("%.1f", 1.0 * sum / cnt / 60);
	return 0;
}

在这里插入图片描述

本题思路

AC代码是贪心寻找最早服务结束的窗口,让客户使用,并计算等待时间和结束时间
要注意的细节有

  • 17:00:00到达也是有效客户,并为其提供服务
  • 就算时间超过17:00:00仍在排队等待,也是有效客户,银行也是要提供服务的
  • 17:00:01到达为无效客户,不参与统计计算

AC代码

#include <bits/stdc++.h>
using namespace std;
int N, K;
struct Node{
	int start;//到银行时间用秒表示 
	int d;//处理时间用秒表示 
	Node(){}
	Node(int ss, int dd)
	{
		start = ss;
		d = dd;
	}
}nodes[10005];
struct Window{
	int end = 8 * 3600;//当前用户的结束时间 
	bool status = true;//true:可用,false:不可用 
	Window(){}
	Window(int e, bool s)
	{
		end = e;
		status = s;
	}
}windows[105];
bool cmp(Node n1, Node n2)
{
	return n1.start < n2.start;
}
//时间点用秒表示(距离00:00:00多少秒) 
int getSecond(int h, int m, int s)
{
	return h * 3600 + m * 60 + s;
}
int main(int argc, char *argv[]) {
	scanf("%d%d", &N, &K);
	int sum = 0, num = 0;//等待时间总秒数sum,总人数num 
	int open = 8 * 3600;//银行开门时间
	int end = 17 * 3600;
	for(int i = 0; i < N; ++i)
	{
		int h, m ,s ,d;
		scanf("%d:%d:%d %d", &h, &m, &s, &d);
		int ss = getSecond(h, m, s);
		int dd = d * 60;
		if(ss > end)//关门来晚了 
			continue;
		nodes[num++] = Node(ss, dd);//有效客户 
	}
	sort(nodes, nodes + num, cmp);
	
	for(int i = 0; i < num; ++i)
	{
		//窗口编号:winID,最早结束时间minEndTime 
		int winID = -1, minEndTime = 0x3fffffff;
		for(int j = 0; j < K; ++j)
		{
			if(windows[j].end < minEndTime)
			{
				minEndTime = windows[j].end;
				winID = j;
			}
		}
		if(windows[winID].end <= nodes[i].start)
		{
			windows[winID].end = nodes[i].start + nodes[i].d; 
		}
		else
		{
			sum += (windows[winID].end - nodes[i].start); 
			windows[winID].end += nodes[i].d;
		}
	}
	if(num == 0)
		printf("0.0");
	else
		printf("%.1f", 1.0 * sum / num / 60);
	return 0;
}

几个测试用例

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
ans
8.2

3 3
08:01:00 60
08:00:00 30
08:00:02 2
ans
0.0

3 3
07:55:00 16
17:00:01 2
07:59:59 15
ans
2.5

3 3
16:59:59 20
17:00:01 2
17:00:00 10
ans
0.0

3 3
17:00:00 10
17:01:00 2
17:03:00 9
ans
0.0



4 1
16:55:00 4
16:58:00 10
16:59:00 2
17:00:00 10
ans
5.5


3 1
16:55:00 3
16:56:00 2
16:59:00 10
ans
1.0
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值