题目
A table tennis club has N tables available to the public. The tables are numbered from 1 to N. For any pair of players, if there are some tables open when they arrive, they will be assigned to the available table with the smallest number. If all the tables are occupied, they will have to wait in a queue. It is assumed that every pair of players can play for at most 2 hours.
Your job is to count for everyone in queue their waiting time, and for each table the number of players it has served for the day.
One thing that makes this procedure a bit complicated is that the club reserves some tables for their VIP members. When a VIP table is open, the first VIP pair in the queue will have the priviledge to take it. However, if there is no VIP in the queue, the next pair of players can take it. On the other hand, if when it is the turn of a VIP pair, yet no VIP table is available, they can be assigned as any ordinary players.
Input Specification:
Each input file contains one test case. For each case, the first line contains an integer N (<=10000) - the total number of pairs of players. Then N lines follow, each contains 2 times and a VIP tag: HH:MM:SS - the arriving time, P - the playing time in minutes of a pair of players, and tag - which is 1 if they hold a VIP card, or 0 if not. It is guaranteed that the arriving time is between 08:00:00 and 21:00:00 while the club is open. It is assumed that no two customers arrives at the same time. Following the players’ info, there are 2 positive integers: K (<=100) - the number of tables, and M (< K) - the number of VIP tables. The last line contains M table numbers.
Output Specification:
For each test case, first print the arriving time, serving time and the waiting time for each pair of players in the format shown by the sample. Then print in a line the number of players served by each table. Notice that the output must be listed in chronological order of the serving time. The waiting time must be rounded up to an integer minute(s). If one cannot get a table before the closing time, their information must NOT be printed.
Sample Input:
9
20:52:00 10 0
08:00:00 20 0
08:02:00 30 0
20:51:00 10 0
08:10:00 5 0
08:12:00 10 1
20:50:00 10 0
08:01:30 15 1
20:53:00 10 1
3 1
2
Sample Output:
08:00:00 08:00:00 0
08:01:30 08:01:30 0
08:02:00 08:02:00 0
08:12:00 08:16:30 5
08:10:00 08:20:00 10
20:50:00 20:50:00 0
20:51:00 20:51:00 0
20:52:00 20:52:00 0
3 3 2
解析
这道题目重点需要注意球桌与球员的分配规则。将队员按照到达时间排列,则规则可以总结如下:
1. 排列在队前的球员是VIP球员,
1) 寻找在他到达前已结束serve的编号最小的VIP球桌
2)如果到达之前没有结束serve的VIP球桌,则寻找编号最小的空闲的普通球桌
3)如果球员到达时无空闲球桌,则寻找结束时间最早的球桌,如果有多个球桌同时结束,则优先分配VIP球桌,如果无VIP球桌则优先分配编号最小的球桌
2. 排列在最前面的是普通球员
1)寻找球员到达时空闲球桌中编号最小的球桌分配给他
2)如果球员到达时无空闲球桌,则分配结束时间最早的编号最小的球桌分配给他
总结如下:
1、有球桌空闲,则优先分配编号最小的,如果是VIP球员,则优先分配空闲中的编号最小的VIP球桌
2、无球桌空闲,则需要等待,分配结束时间最早的球桌中编号最小的,如果是VIP球员,则选择符合条件中编号最小的
需要格外注意的是VIP球员优先分配VIP球桌。
代码
#include <bits/stdc++.h>
#include <iostream>
using namespace std;
struct Club
{
int endTime,count;
bool isVip;
Club(int end=0,int c=0,bool vip=false):endTime(end),count(c),isVip(vip) {}
};
struct Person
{
int arrive,start,cost;
bool isVip;
Person(int arr,int s,int c,bool vip):arrive(arr),start(s),cost(c),isVip(vip) {}
};
bool cmp(Person &p1,Person &p2){
return p1.arrive<p2.arrive;
}
bool cmp2(Person &p1,Person &p2){
return p1.start<p2.start;
}
void input(vector<Club> &club,vector<Person> &person){
int n;
scanf("%d",&n);
int eight=8*3600,nine=21*3600;
for(int i=0;i<n;i++){
int h,m,s,p,f;
scanf("%d:%d:%d %d %d",&h,&m,&s,&p,&f);
int arr=h*3600+m*60+s;
p=min(p,120)*60;
if(arr>=nine) continue;
//所有来打球的人初始化开始时间为晚上21点以后
if(f==1){
person.emplace_back(arr,nine+10,p,true);
}
else{
person.emplace_back(arr,nine+10,p,false);
}
}
int m,k;
scanf("%d%d",&m,&k);
for(int i=0;i<=m;i++){
club.emplace_back(eight,0,false);
}
for(int i=0;i<k;i++){
int num;
scanf("%d",&num);
club[num].isVip=true;
}
}
void show(Person &p){
if(p.start>=21*3600) return;
int arrh=p.arrive/3600,arrm=p.arrive%3600/60,arrs=p.arrive%60;
int sh=p.start/3600,sm=p.start%3600/60,ss=p.start%60;
double err=(p.start-p.arrive)/60.0;
printf("%02d:%02d:%02d %02d:%02d:%02d %.0f\n",arrh,arrm,arrs,sh,sm,ss,round(err));
}
//分配打球的player到特定的球台
void allocate(int index,int per,vector<Club> &club,vector<Person> &person){
if(person[per].arrive<=club[index].endTime){
person[per].start=club[index].endTime;
}
else{
person[per].start=person[per].arrive;
}
club[index].endTime=person[per].start+person[per].cost;
club[index].count++;
}
int main(){
vector<Club> club;
vector<Person> person;
input(club,person);
int len=person.size();
int lenc=club.size();
sort(person.begin(),person.end(),cmp);
int per=0,nine=21*3600;
for(int i=0;i<len&&per<len;i++){
int earlyEnd=INT_MAX,index=-1;
//如果没有球桌空闲则找到当前结束时间最早的球桌,如果有球桌空闲,则找到编号最小的空闲的球桌
for(int j=1;j<lenc;j++){
//在队列最前的球员到达之前,找到已空闲球桌中编号最小的
if(club[j].endTime<=person[per].arrive){
earlyEnd=club[j].endTime;
index=j;
break;
}
if(earlyEnd>club[j].endTime){
earlyEnd=club[j].endTime;
index=j;
}
}
if(earlyEnd>=nine) break;
if(club[index].isVip){ //如果当前空闲或结束时间最早的球桌是VIP球桌
int k=per;
//在当前等待人员中找到最靠前的VIP球员且还未开始打球
while(k<len){
if(person[k].isVip==true&&person[k].start>=nine)
break;
k++;
}
//如果找到VIP球员且球员到达时间早于球桌结束时间则把球桌分配给他,如果没有找到则把球桌分配给队列最靠前球员
if(k<len&&person[k].arrive<=earlyEnd){
allocate(index,k,club,person);
}
else{
allocate(index,per,club,person);
}
}
else{ //如果当前球桌不是VIP球桌
//如果当前最靠前的球员是VIP球员,则寻找球员到达时的空闲球桌中找到编号最小的VIP球桌分配给他
//如果球员到达时无空闲球桌,则分配结束时间最早的球桌给他
if(person[per].isVip==true){
int vipearlyEnd=INT_MAX,vipindex=-1;
for(int j=1;j<lenc;j++){
//寻找球员到达时已结束的球桌中编号最小的VIP球桌
if(club[j].isVip&&club[j].endTime<=person[per].arrive){
vipearlyEnd=club[j].endTime;
vipindex=j;
break;
}
}
//如果找到则分配VIP球桌,否则分配当前结束时间最早的球桌
if(vipindex!=-1&&person[per].arrive>=vipearlyEnd){
allocate(vipindex,per,club,person);
}
else{
allocate(index,per,club,person);
}
}
else{ //如果球桌不是VIP球桌,球员不是VIP球员,则分配当前球桌给当前球员
allocate(index,per,club,person);
}
}
//per指向队列中第一个还未开始的球员
while(per<len&&person[per].start<=nine){
per++;
}
}
sort(person.begin(),person.end(),cmp2);
for(int i=0;i<len&&person[i].start<nine;i++){
show(person[i]);
}
for(int i=1;i<lenc;i++){
if(i==1) printf("%d",club[i].count);
else printf(" %d",club[i].count);
}
return 0;
}