#include<bits/stdc++.h>
using namespace std;
int N ,K;
int EndTime[100]; // 上一个客户结束服务的时间
struct Customer{
int arriveTime; // 客户到达时间
int processTime; // 客户办理业务的时间
}cust[10000];
struct cmp{
bool operator()(const int &a, const int &b) {
// 优先队列的重载小于号是常引用并且是const函数
return cust[a].arriveTime > cust[b].arriveTime;
}
};
priority_queue<int, vector<int>, cmp> Q; // 等待队列,存放编号(根据到达时间来排序编号)
int main() {
double ans = 0.0;
int realN = 0;
cin >> N >> K;
for(int i = 0;i < N;++i) {
int hour, minute, second, p;
scanf("%d:%d:%d %d\n", &hour, &minute, &second, &p);
if(p > 60) p = 60;
cust[i].arriveTime = (hour*60 + minute) * 60 + second;
cust[i].processTime = p*60;
if(cust[i].arriveTime <= 61200){
Q.push(i);
realN++;
}
}
for(int i = 0;i < K;++i)
EndTime[i] = 28800;
while(!Q.empty()){
// 寻找最早结束时间的窗口
int popWindow = 0;
for(int windowID = 1;windowID < K;++windowID)
if(EndTime[windowID] < EndTime[popWindow])
popWindow = windowID;
Customer &nowCust = cust[Q.top()];
if(nowCust.arriveTime < EndTime[popWindow]) {
// 来早了需要等待
ans += (EndTime[popWindow] - nowCust.arriveTime);
EndTime[popWindow] += nowCust.processTime;
} else {
// 来晚了可以直接开始
EndTime[popWindow] = nowCust.arriveTime + nowCust.processTime;
}
Q.pop();
}
printf("%.1lf\n", ans/(60.0*realN));
return 0;
}
折磨了一天,终于用模拟时间的方法做出来了!!!!很开心
#include<bits/stdc++.h>
using namespace std;
int N ,K;
struct Cust{
int arriveTime;
int processTime;
}cust[10000];
struct cmp{
bool operator()(const int &a, const int &b) {
// 优先队列的重载小于号是常引用并且是const函数
return cust[a].arriveTime > cust[b].arriveTime;
}
};
priority_queue<int, vector<int>, cmp> Q; // 等待队列,存放编号
int EndTime[100]; // 第i个窗口上一次的客户离开窗口的时间
int EnterTime[100]; // 第i个窗口这一次的客户进入窗口的时间
queue<int> window[100]; // 模拟窗口,队列最多只有一个人
double ans = 0.0; // 记录总等待时间
int realN = 0; // 有效的客户个数
void get_ans() {
/*模拟时间, 每一秒都根据窗口是否有人来处理
对于每一秒的所有窗口:
如果窗口有人:
那就等到这个人结束业务的时间让他离开,更新离开时间
如果窗口没人:
那就在黄线外让最早到达的人进入窗口,更新进入时间
如果最早到达的人到达的时候没有窗口结束业务,那就等到第一个窗口业务结束,然后进入
如果最早到达的人到达的时候有空闲窗口,那就直接进入,无需等待
*/
for(int second = 28800;second <= 61200 || !Q.empty();++second) {
//Q中都是有效的客户
for(int winID = 0;winID < K;++winID) {
// 检查窗口
queue<int> &win = window[winID];
if(!win.empty()) {
// 窗口有人在办理业务
// 如果到了业务办理结束的时间就让这个人离开窗口,并记录用户离开窗口的时间
if(second == (EnterTime[winID] + cust[win.front()].processTime)) {
win.pop();
EndTime[winID] = second;
}
}
//这个if必须放在上面一个if下面,因为在上一个if pop之后这里的if负责让客户进入
if(win.empty() && !Q.empty()) {
// 窗口空且有人
// 如果到了当前窗口业务结束的时间
if(second == EndTime[winID]){
int custID = Q.top(); // 这个人将要进入窗口,所以记录他来更新进入时间和总等待时间
if(cust[custID].arriveTime < EndTime[winID]) {
// 来早了窗口业务还没结束,等到业务结束
ans += (second - cust[custID].arriveTime);
EnterTime[winID] = EndTime[winID]; // 等到业务结束才进去
} else {
EnterTime[winID] = cust[custID].arriveTime; // 如果到达时,窗口是空闲的,就可以直接进去,不需要等待
}
win.push(custID); // 进入窗口
Q.pop(); // 黄线外的等待队列少一人
}
}
} // end_innner for
} // end_outter for
}
int main() {
cin >> N >> K;
for(int i = 0;i < N;++i) {
int hour, minute, second, p;
scanf("%d:%d:%d %d\n", &hour, &minute, &second, &p);
if(p > 60) p = 60;
cust[i].arriveTime = (hour*60 + minute) * 60 + second;
cust[i].processTime = p*60;
if(cust[i].arriveTime <= 61200){
Q.push(i);
realN++;
}
}
fill(EndTime, EndTime+K, 28800);
fill(EnterTime, EnterTime+K, 28800);
get_ans();
printf("%.1lf\n", ans/(60.0*realN)); //
return 0;
}