PAT.A1026 Table Tennis

返回目录在这里插入图片描述

题意

有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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小怪兽会微笑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值