【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 (≤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.

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

中文题目:

假设一家银行有 K 个服务窗口。 窗户前面有一条黄线,将等候区分为两部分。 所有客户都必须在黄线后面排队等候,直到轮到他/她服务并且有可用的窗口为止。 假定一个窗口不能被单个客户占用超过 1 小时,即如果某位顾客的业务已经办理了一小时,则立即终止此项业务。 现在给定每个客户的到达时间 T 和业务办理时间 P,请计算所有客户的平均等待时间。 输入格式 第一行包含两个整数 N 和 K,分别表示客户数量以及窗口数量。 接下来 N 行,每行包含两个时间,分别是一个客户的到达时间,用 HH:MM:SS 表示,以及一个客户的业务办理时间 P(单位:分钟)。 HH 在 [00,23] 范围内,MM 和 SS 都在 [00,59] 范围内。 所有客户的到达时间均不相同。 请注意,银行的营业时间为 08:00 至 17:00。 任何人提前到达都必须排队等候至 08:00,而任何人来得太晚(在 17:00:01 或之后到达)都将不被服务也无需计入平均值。 注意只要客户在17:00之前排上队,则即使办理业务时超过17:00,也会被服务。 输出格式 输出平均等待时间(单位:分钟),结果保留一位小数。 注意,从到达银行至开始办理业务这一期间视为等待期间。

AC代码:

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
typedef struct S
{
	int come, go;
	int serve_time;
}S;

bool cmp1(S s1, S s2)
{
	return s1.come < s2.come;
}

bool cmp2(S s1, S s2)
{
	return s1.go < s2.go;
}


int main()
{
	int n = 0;
	int wind = 0;
	cin >> n >> wind; //人数和窗口数
	vector<S> v;
	int sum_time = 0;
	int cnt = 0;
	for (int i = 0; i < n; i++)
	{
		S tmp;
		int hh, mm, ss;
		int serve_time;
		int begin_time, end_time;
		scanf("%02d:%02d:%02d %d", &hh, &mm, &ss, &serve_time);
		begin_time = hh * 3600 + mm * 60 + ss;
		if (begin_time >= 17 * 3600 + 1)
			continue;
		if (begin_time < 8 * 3600)
			sum_time += 8 * 3600 - begin_time;
		end_time = ((begin_time < 8 * 3600 )? 8 * 3600 : begin_time) + (serve_time > 60 ? 60 : serve_time) * 60;
		tmp.come = begin_time;	
		tmp.go = end_time;
		tmp.serve_time = serve_time;
		v.push_back(tmp);
		++cnt;
	}
	sort(v.begin(), v.end(), cmp1);  //以到来时间为基准从早到晚排序,即服务顺序
	int busy_wind = 0;
	vector<S> v2;
	for (int i = 0; i < v.size(); i++)
	{
		if (busy_wind < wind)
		{
			++busy_wind;
			v2.push_back(v[i]);
		}
		else
		{
			//窗口已满,需要进一步判断
			sort(v2.begin(), v2.end(), cmp2);
			if (v[i].come < v2[0].go)
			{
				sum_time += v2[0].go - v[i].come;
				v[i].go = v2[0].go + v[i].serve_time * 60;
				v2.erase(v2.end() - wind);
				v2.push_back(v[i]);
			}
			else
			{
				v2.erase(v2.end() - wind);
				v2.push_back(v[i]);
			}
		}
	}
	(!cnt) ? printf("0.0\n") : printf("%.1lf", sum_time / 60.0 / cnt);
	return 0;
}

 1. 把起始时间,开始时间,服务时间都转化为以秒为单位是个很机智的做法。

2.由于对于优先队列等较高级数据结构不熟悉,所以代码中只用到了vector

3. 要点就是,先把数据以合适的方式存入,再计算总的等待时间,注意每个人早于8点到达,至8点的这段时间也属于等待时间

流程&注意点:

1.第一个for循环中的end_time并非真正的end_time,因为每个人的开始服务时间并不一定等于到达时间,所以结束时间也就不能用到达时间加服务时间来计算,这也是开始的时候犯得一个错误。若某人到达时,窗口已满,则它的服务时间应等于窗口中最早离开的人的离开时间加自己的服务时间,即自己的离开时间。

2.vector v2中就是用来存放窗口中服务的人的,每次都要排序一下,使v[0]存放最早离开的人

3.最后除应该除真正的服务时间,而非最开始存入的n。(并不算很细的一个细节)

4.v2.erase(v2.end() - wind) 用于删除最先离开的那个人,这个应该是有更直接的写法的,但是目前忘了。。。这些操作在优先队列中都有很方便的实现方法

两种优先队列解法

#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 10005;
struct person {
    int come, time;
} p[maxn];
int cmp(person p1, person p2) { return p1.come < p2.come; }
int n, k, cnt, total;
int main() {
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i++) {
        int hh, ss, mm, tt;
        scanf("%d:%d:%d %d", &hh, &mm, &ss, &tt);
        int sum = hh * 3600 + mm * 60 + ss;
        if (sum > 61200) continue;
        p[++cnt].time = tt * 60;
        p[cnt].come = sum;
    }
    sort(p + 1, p + 1 + cnt, cmp);
    priority_queue<int, vector<int>, greater<int> > q;
    for (int i = 1; i <= k; ++i) q.push(28800);
    for (int i = 1; i <= cnt; ++i) {
        if (q.top() <= p[i].come) {
            q.push(p[i].come + p[i].time);
            q.pop();
        } else {
            total += q.top() - p[i].come;
            q.push(q.top() + p[i].time);
            q.pop();
        }
    }
    (!cnt) ? printf("0.0\n") : printf("%.1lf", ((double)total/60.0)/(double) cnt);
    return 0;
}

 

//1071
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int N = 10010, M = 110;

int n, m;

struct Person{
	//计算到凌晨0:0分的秒数
	int arrive_time;
	int serve_time;  //服务时间也是改成秒数
	bool operator<(const Person& t) {	//按到达时间进行排序 
		return arrive_time < t.arrive_time;
	}
}persons[N];
/*
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
*/
int main() {
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		int hour, minute, second, serve_time;
		//格式化输入
		scanf("%d:%d:%d %d", &hour, &minute, &second, &serve_time);
		serve_time = min(serve_time, 60);
		persons[i] = { hour * 3600 + minute * 60 + second,serve_time*60 };
	}
	priority_queue<int, vector<int>, greater<int>>windows;
	sort(persons, persons + n);

	for (int i = 0; i < m; i++) {
		windows.push(8 * 3600);//初始化m个窗口
	}
	
	int cnt = 0;
	double sum = 0;
	for (int i=0;i<n;i++) {
		auto person=persons[i];
		auto w = windows.top();
		windows.pop();
		//用户来的时间太晚了,直接break 
		if (person.arrive_time > 17 * 3600)break;
		int start_serve_time = max(person.arrive_time, w);//顾客可能是一来就有了,或者是要等
		sum += start_serve_time - person.arrive_time;  // 等待时间:开始服务时间-到达时间
		windows.push(start_serve_time + person.serve_time);
		cnt++;
	}
	
	printf("%.1lf\n", (double)sum / cnt / 60);
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值