题目分析:
本题我第一次尝试去做的时候用的是优先队列,但是效率不仅代码量很大,而且还有测试样例过不去,很显然没有找到一个好的数据结构来解决这道题目(随着逐渐的刷PAT甲级的题会发现有时选择一个好的解题方向真的比一些花里胡哨的技巧重要的多),对于本题,我们需要模拟的是一个去银行接受服务的过程,银行有k个窗口,而在8点开门之前所有到达的人都在门外排队(在8点后到达的人如果有人则需要排队,窗口中有空位则会选择最空闲的进行自己的服务),首先我们需要对n个用户按照到达的时间进行排序,然后建立一个window数组存放每个窗口结束被占用的的时间(最初始k个窗口都为28800,这是8点转化成了秒为单位,本题所有的时间都转化成了秒,方便计算,而上限值则是17点相对的秒数61200秒,用户在17点之后到达则无法接受服务且不会被加入有效等待人数中),对于用户队列,我们每次选择一个人,这个人将选择此时k个窗口中时间最小的,模拟用户接受服务的过程,而这个过程分为两种情况(1.轮到这个用户的时候,最小的窗口时间比用户到达的时间小,则表示在用户到达之前这个窗口已经空出来了,且没有人占用它,则这个用户的等待时间则为0,此时更新这个窗口的时间为该用户达到时间+该用户需要服务的时间 2.轮到这个用户的时候,最小的窗口时间比用户到达的时间大,则表示用户在到达的时候最近的一个窗口还正在被占用,则用户就需要等待的时间为:这个窗口的结束占用时间-用户到达的时间,然后这个用户接受服务,则也需要更新这个窗口的结束被占用时间为此时窗口时间+用户需要服务的时间)对于输入n为0的情况特判一下
#include<iostream>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std; struct Node{
int come, time; //记录每个人到达的时间和需要服务的时间
}; bool cmp(Node a, Node b){
return a.come < b.come;
} int main(){
int n, k;
while(scanf("%d%d", &n, &k) != EOF){
vector<Node> cus;
for(int i = ; i <= n; i++){
int hh, mm, ss, time;
scanf("%d:%d:%d%d", &hh, &mm, &ss, &time);
Node peo;
peo.come = hh * + mm * + ss;//到达的时间和被服务时间为秒
peo.time = time * ;
if(peo.come <= ) cus.push_back(peo); //只有在17点之前的人才会被服务
}
sort(cus.begin(), cus.end(), cmp);
int wait_sum = ; //总等待时间
vector<int> window(k, ); //对k个窗口初始化时间为8点 == 28800秒
for(int i = ; i < cus.size(); i++){ //对于所有排队的用户一个一个遍历(模拟寻找窗口的过程
int mi = window[];
int index = ;
for(int j = ; j < k; j++){ //找到窗口时间最小的
if(window[j] < mi){
mi = window[j];
index = j;
}
}
if(window[index] <= cus[i].come){
window[index] = cus[i].come + cus[i].time;
}else{
wait_sum += window[index] - cus[i].come;
window[index] += cus[i].time;
}
// cout<<"wait_sum"<<wait_sum<<endl;
}
if(cus.size() == ) printf("0.0\n");
else{
printf("%.1lf\n", wait_sum * 1.0 / cus.size() / );
}
}
return ;
}