1026 Table Tennis

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

题目大意

网球俱乐部有n个桌子,编号为1到n。每对运动员到达时,若有空闲的桌子,则选择编号最小的;若无空闲的桌子,则排队等候。某些桌子已被VIP会员预订,一旦有VIP桌空闲,队伍中第一个VIP会员可优先进入。到达时间保证在8:00到21:00之间。若运动员21:00之前等不到座位,则不参与计算。计算每对运动员的等待时间,每个桌子服务过的人数。

思路

先将所有运动员放入一个队伍(结构体存储,到达时间排序,并用flag数组判断该运动员是否已上桌)。每个桌子设置一个计时器counter,记录当前服务进行完的时间。开始循环,每次选择counter最小的桌子minp,已到达的队伍中第一个队员(需保证未超过21:00,若超过,直接退出循环)。接下来的处理分为两大类:

  • 选择的minp为vip桌,检测队伍中是否有vip会员,若有,则选中第一个vip;若无,则仍选中第一个队员。
  • 选择的minp为非vip桌,两种情况:①队列中第一个为vip会员,则再次遍历桌子,看是否有vip桌子同样满足空闲时间最早,若有,则选中该桌子。②队列中第一个为非vip,则仍选中原先的minp。 (这个①极易忽视)

接下来将数据进行统一更新:
选中队员的flag更新为true,选中桌子的服务人数num加1,队员的serve_time有两种情况:

  • counter>arrive_time,即该桌子空闲时运动员还未到达,则serve_time更新为arrive_time。
  • counter<arrive_time,即运动员到达时该桌子还未空闲,则serve_time更新为counter。

而桌子的counter更新为serve_time+play_time。
以下为我遇到的巨坑!足足坑了我俩小时…

  • 题目虽然说保证所有人都在8:00到21:00到达(我不知道是不是我对guarantee的理解有错误…),实际上必须要考虑21:00以后到达的运动员并将其排除。
  • 每个运动员游玩时间不超过2小时,我又将它理解成给的数据都不超过2小时了(因为之前确实有过这样的题),事实上,超过2小时的要强制改为2小时。
  • 再就是我上面所说极易忽视的①,VIP会员优先选择VIP桌,而不是直接选择第一个空闲桌,这是题目中的隐含条件。

AC代码

#include <iostream>
#include <cstdio>
#include <algorithm> 
using namespace std;

struct player{
	int play; //服务时间(秒)
	int tag; //是否为VIP 
	int arrive; //到达时间(秒)
	int serve; //服务开始时间(秒) 
}P[10001];
bool flag[10001] = {false}; //某运动员是否已上桌 

bool cmp1(player &a, player &b){
	return a.arrive < b.arrive;
}

void get_time(player &a){
	int w = (a.serve - a.arrive + 30) / 60;
	printf("%02d:%02d:%02d ", a.arrive / 3600, 
		a.arrive % 3600 / 60, a.arrive % 60);
	printf("%02d:%02d:%02d ", a.serve / 3600, 
		a.serve % 3600 / 60, a.serve % 60);
	printf("%d\n", w);
}

int main(){
	int n, k, m; //运动员人数 座位个数 VIP座位个数 
	int h1, m1, s1; //到达时间
	scanf("%d", &n);
	for(int i = 0; i < n; i++){
		scanf("%d:%d:%d %d %d", &h1, &m1,
			&s1, &P[i].play, &P[i].tag);
		P[i].play = min(7200, P[i].play * 60);
		P[i].arrive = h1 * 3600 + m1 * 60 + s1;	
	}
	scanf("%d%d", &k, &m);
	bool vip[101] = {false}; //是否为VIP桌
	int t;
	for(int i = 0; i < m; i++){
		scanf("%d", &t);
		vip[t] = true;
	}
	sort(P, P + n, cmp1);
	int counter[101]; //计时器
	int num[101] = {0}; //每台桌子服务人数 
	fill(counter, counter + k + 1, 8 * 3600);
	int i = 0;
	while(i < n){
		int min = 21 * 3600, minp = -1;
		for(int j = 1; j <= k; j++){ //选择最早结束的桌子 
			if(counter[j] < min){
				min = counter[j];
				minp = j;
			}
		}
		if(minp == -1) //没有21:00前结束的桌子
			break;
		while(flag[i] == true && i < n)
			i++; //找到队伍中第一个运动员
		if(i >= n) break;
		int cho = i; //被选运动员的序号
		if(vip[minp] == true){ //选中vip桌
			for(int j = 0; j < n; j++){
				if(P[j].tag == 1 && flag[j] == false
				&& P[j].arrive <= counter[minp]){
					cho = j;
					break;
				}
			} 
		}
		else if(P[cho].tag == 1){
			for(int j = 1; j <= k; j++){
				if(counter[j] == min && vip[j] == true){
					minp = j;
					break;
				}
			}
		}
		if(P[cho].arrive >= 21 * 3600) break;
		flag[cho] = true;
		P[cho].serve = max(counter[minp], P[cho].arrive);
		counter[minp] = P[cho].serve + P[cho].play;
		get_time(P[cho]);
		num[minp]++;
	}
	for(int i = 1; i <= k; i++){
		if(i != 1) printf(" ");
		printf("%d", num[i]);
	}
	return 0;
}
The following is the data that you can add to your input file (as an example). Notice that the first line is going to be a line representing your own hobbies. In my case, it is the Vitaly,table tennis,chess,hacking line. Your goal is to create a class called Student. Every Student will contain a name (String) and an ArrayList<String> storing hobbies. Then, you will add all those students from the file into an ArrayList<Student>, with each Student having a separate name and ArrayList of hobbies. Here is an example file containing students (the first line will always represent yourself). NOTE: eventually, we will have a different file containing all our real names and hobbies so that we could find out with how many people each of us share the same hobby. Vitaly,table tennis,chess,hacking Sean,cooking,guitar,rainbow six Nolan,gym,piano,reading,video games Jack,cooking,swimming,music Ray,piano,video games,volleyball Emily,crochet,drawing,gardening,tuba,violin Hudson,anime,video games,trumpet Matt,piano,Reading,video games,traveling Alex,swimming,video games,saxophone Roman,piano,dancing,art Teddy,chess,lifting,swimming Sarah,baking,reading,singing,theatre Maya,violin,knitting,reading,billiards Amy,art,gaming,guitar,table tennis Daniel,video games,tennis,soccer,biking,trumpet Derek,cooking,flute,gaming,swimming,table tennis Daisey,video games,guitar,cleaning,drawing,animated shows,reading,shopping Lily,flute,ocarina,video games,baking Stella,roller skating,sudoku,watching baseball,harp Sophie,viola,ukulele,piano,video games
06-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值