​返回目录​

PAT.A1026 Table Tennis_2d

题意

有K张乒乓球桌(编号为1~K)于8.00:00 ~ 21:00:00开放,每对球员(由于球员总是成对,因此为了避免歧义,以下叙述中都把“一对球员”叙述为“一个球员”) 到达时总是选择当前空闲的最小编号的球桌进行训练,且训练时长超过2h,会被强制压缩成2h,而如果到达时没有球桌空闲,则排成队列等待。需要注意的是,这K张球桌中有M张是VIP球桌,如果存在VIP球桌空闲,且等待队列中存在VIP球员,那么等待队列中第一个VIP球员将前往编号最小的VIP球桌训练;如果存在VIP球桌空闲,等待队列中没有VIP球员,那么VIP球桌将被分配给等待队列中第一个普通球员; 而如果当前没有VIP球桌空闲,那么VIP球员将被看作普通球员处理。现在给出每个球员的到达时间、训练时长、是否是VIP球员以及给出球桌数和所有VIP球桌编号,求所有在关门前得到训练的球员的到达时间、训练开始时间、等待时长(四舍五入至整数)以及所有球桌当天的服务人数。注意:所有在10:0之后(含2100:00)还没有得到训练的球员将不再训练,且不需要输出。

样例(可复制)

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
//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

提供易错几个测试数据

2
08:00:00 130 0
09:00:00 10 0
1 0
//output该数据测试每个球员都必须在2h训练内完成
08:00:00 08:00:00 0
09:00:00 10:00:00 60
2
2
21:00:00 10 1
21:01:00 10 1
3 3
1 2 3
//output该数据测试所有球员都在21点后到达
0 0 0
2
08:00:00 10 1
08:05:00 10 1
3 2
2 3
//output该数据测试vip球员是否优先选择vip球桌
08:00:00 08:00:00 0
08:05:00 08:05:00 0
0 1 1

注意点

  1. 本题模拟难度较大,需要注意的点有很多,下面一一列举
  2. 如果vip球员来的时候有vip球桌和普通球桌都空闲,vip球员会优先选择vip球桌
  3. 注意多个球桌都空闲的时候,不是选择球桌上次结束服务时间最早的,而是选择编号最小的
  4. 注意最后的结果按照球员服务的开始时间进行排序,而非球员到达时间
  5. 注意以上给出的几个测试易错数据的情况
  6. 四舍五入输出时使用round,注意函数里面要先变成double,否则就已经是整数了。
  7. 本题解法很多,不止本文一种,建议读者按照一个大致思路先自己写出代码,不能过的测试点按照提供的易错数据、注意点和参考代码逐步修改。
#include <bits/stdc++.h>
using namespace std;

struct player{
int come,start,serve,train,vip;//来到时间,开始训练时间,服务时间,是否训练,是否为vip
}pla[10010];//0--n-1
struct table{
int vip,endtime,num;//是否为vip,球桌服务结束时间,服务人数
}tab[110];//1--k
int np,nt,nvip;//球员数量,球桌数量,vip球桌数量
int gettime(int h,int m,int s){
return h*3600+m*60+s;
}
bool cmp1(player a,player b){
return a.come<b.come;
}
bool cmp2(player a,player b){
return a.start<b.start;
}
int main(){
cin>>np;
int h,m,s,vipnum,sevre;
for(int i=0;i<np;i++){
scanf("%d:%d:%d %d %d",&h,&m,&s,&pla[i].serve,&pla[i].vip);
pla[i].serve=min(pla[i].serve*60,7200);
pla[i].come=gettime(h,m,s);
pla[i].start=INT_MAX;
}
cin>>nt>>nvip;
int st=gettime(8,0,0),ed=gettime(21,0,0);
for(int i=1;i<=nt;i++)tab[i].endtime=st;//初始化球桌
while(nvip--){
scanf("%d",&vipnum);
tab[vipnum].vip=1;
}
sort(pla,pla+np,cmp1);//按到达时间排序
int numl=0,numr=0;//numl为当前队列中来的最早的没有被服务的编号,numr为队列中endtime后的第一个人
while(numl<np){
while(pla[numl].train)numl++;//找出队列中第一个没有被服务
if(pla[numl].come>=ed)break;//如果第一个没有被服务的人在21点后,则不服务了
//选出合适的table
int minendtime=INT_MAX,cho;
for(int i=1;i<=nt;i++){
if(tab[i].endtime<minendtime){
cho=i;
minendtime=tab[i].endtime;
}
}
for(int i=1;i<=nt;i++){
//vip球员优先选择vip球桌,非vip球员选择编号最小的空闲球桌
if(pla[numl].come>=tab[i].endtime&&(pla[numl].vip&&tab[i].vip||!pla[numl].vip)){
cho=i;
break;
}
}
if(minendtime>=ed)break;//如果已经21点后,则不服务了
//找出队列中endtime后的第一个人
while(pla[numr].come<=tab[cho].endtime&&numr<np)numr++;
if(numl<numr){//endtime前有人在等
if(tab[cho].vip){//是vip球桌
int i;
for(i=numl;i<numr;i++){
if(pla[i].vip&&!pla[i].train)break;
}
if(i==numr)i=numl;//没有找到了没有服务过的vip球员
pla[i].train=1;
pla[i].start=tab[cho].endtime;
tab[cho].endtime+=pla[i].serve;

}else{//非vip球桌
pla[numl].train=1;
pla[numl].start=tab[cho].endtime;
tab[cho].endtime+=pla[numl].serve;
}
tab[cho].num++;
}else if(numl<np){//没有人等,则选择第一个来的即可
pla[numl].train=1;
tab[cho].endtime=pla[numl].come+pla[numl].serve;
pla[numl].start=pla[numl].come;
tab[cho].num++;
}
}
sort(pla,pla+np,cmp2);//按服务开始时间排序
for(int i=0;i<np;i++){
if(!pla[i].train)break;
int co=pla[i].come,sta=pla[i].start;
int ans=(int)round((sta-co)/60.0);
printf("%02d:%02d:%02d %02d:%02d:%02d %d\n",co/3600,co%3600/60,co%60,sta/3600,sta%3600/60,sta%60,ans);
}
for(int i=1;i<=nt;i++){
printf("%d",tab[i].num);
if(i<nt)printf(" ");
}
return 0;
}