1026 Table Tennis (30 point(s)) - C语言 PAT 甲级

1026 Table Tennis (30 point(s))

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 对球友,输入每对球友到达的时间(08:00:00 - 21:00:00)、玩耍的时间(多于 2 小时的按照 2 小时算)、VIP 身份(0 非 VIP,1 是 VIP);有 K 张球桌,其中 M 张球桌是 VIP 球桌,输入的最后一行是 VIP 球桌的编号;

如果 VIP 桌子有空闲,队列中第一对 VIP 球员优先玩耍,即插队,若队列中没有 VIP 球友,才可以给普通球友玩耍;如果没有 VIP 桌子空闲,VIP 球友没有特权,当作普通球友处理;

输出每对球友的到达时间、开始玩耍的时间、等待的时间(结果四舍五入);并输出每张球桌服务的次数;

设计思路:

注意:有多张空闲桌子的时候,非 VIP 用户选桌子编号最小的;当有 VIP 空桌时,VIP 用户会优先在 VIP 桌中选编号最小的;

1.两个结构体分别表示每对球友信息和球桌信息,第一次按照到达时间排序,即生成球友的等待队列,服务完成后,再根据开始时间排序输出;

2.总结一下本程序中提供服务的逻辑层次:

  • while 等待队列非空
    • 若队首是服务过的用户
      • 队首直接出列,continue
    • 根据队首的到达时间,寻找一张编号最小的空闲桌子或结束最早的
    • if 找到的是 VIP 桌
      • 队列里有 VIP 用户,选 VIP 用户
    • else 非 VIP 桌
      • 队首是 VIP 用户,寻找一张编号最小的空闲 VIP 桌
    • 若被服务的用户是队首用户
      • 队首出列
编译器:C (gcc)
#include <stdio.h>
#include <stdlib.h>

struct player {
	int arrive, time, vip;
	int start;
};

struct table {
	int end, vip;
	int count;
};

int cmp1(const void *a, const void *b)
{
	struct player *s1 = (struct player*)a, *s2 = (struct player*)b;
	return s1->arrive - s2->arrive;
}

int cmp2(const void *a, const void *b)
{
	struct player *s1 = (struct player*)a, *s2 = (struct player*)b;
	if (s1->start != s2->start)
		return s1->start - s2->start;
	else
		return s2->vip - s1->vip;
}

int main(void)
{
	struct player players[10000] = {0};
	struct table tables[100] = {0};
	int n, k, m;
	int i;

	for (i = 0; i < 100; i++)
		tables[i].end = 8 * 60 * 60;
	scanf("%d", &n);
	i = 0;
	while (i < n) {
		int hh, mm, ss, p;
		scanf("%d:%d:%d %d %d", &hh, &mm, &ss, &p, &players[i].vip);
		players[i].arrive = (hh * 60 + mm) * 60 + ss;
		if (players[i].arrive < 21 * 3600) {
			players[i].time = (p <= 120 ? p * 60 : 120 * 60);
			i++;
		} else {
			n--;
		}
	}
	scanf("%d%d", &k, &m);
	for (i = 0; i < m; i++) {
		int num;
		scanf("%d", &num);
		tables[num - 1].vip = 1;
	}

	qsort(players, n, sizeof(struct player), cmp1);

	i = 0;
	while (i < n) {
		if (players[i].start != 0) {
			i++;
			continue;
		}

		int numtable = 0, minnumtable = 0;
		int numplayer = i;
		for (int j = 0; j < k; j++) {
			if (tables[minnumtable].end > tables[j].end) {
				minnumtable = j;
			}
			if (tables[j].end <= players[i].arrive) {
				numtable = j;
				break;
			}
		}
		if (tables[numtable].end > players[i].arrive) {
			numtable = minnumtable;
		}

		if (tables[numtable].vip == 1) {
			for (int j = i; j < n && players[j].arrive <= tables[numtable].end; j++) {
				if (players[j].vip == 1 && players[j].start == 0) {
					numplayer = j;
					break;
				}
			}
		} else {
			if (players[i].vip == 1) {
				for (int j = 0; j < k; j++) {
					if (tables[j].vip == 1 && (tables[j].end <= players[i].arrive)) {
						numtable = j;
						break;
					}
				}
			}
		}
		
		if (players[numplayer].arrive <= tables[numtable].end) {
			players[numplayer].start = tables[numtable].end;
			tables[numtable].end += players[numplayer].time;
		} else {
			players[numplayer].start = players[numplayer].arrive;
			tables[numtable].end = players[numplayer].arrive + players[numplayer].time;
		}

		if (players[numplayer].start < 21 * 3600) {
			tables[numtable].count++;
		}

		if (numplayer == i)
			i++;
	}

	qsort(players, n, sizeof(struct player), cmp2);

	for (i = 0; i < n && players[i].start < 21 * 3600; i++) {
		printf("%02d:%02d:%02d ", players[i].arrive / 3600, players[i].arrive % 3600 / 60, players[i].arrive % 60);
		printf("%02d:%02d:%02d ", players[i].start / 3600, players[i].start % 3600 / 60, players[i].start % 60);
		printf("%d\n", (int)((players[i].start - players[i].arrive + 30) / 60));
	}
	if (k)
		printf("%d", tables[0].count);
	for (i = 1; i < k; i++)
		printf(" %d", tables[i].count);

	return 0;
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值