PAT 甲级1026 Table Tennis (30 分)
题目
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
规则
个人认为本题的规则还是很坑的,貌似没有说清楚,即当前若有VIP桌子空闲那么分配给当前等待队列中的VIP用户,若没有VIP桌子空闲,则将队列中的VIP用户当成普通用户处理,没有优先级可言。我的坑点之一在于当有VIP桌子空闲但是队列中并没有VIP用户的时候,我以为是将普通桌子分配完之后再将空闲的VIP桌子分配给剩余的普通用户,原来实际上在普通用户的眼里,没有VIP桌子和普通桌子之分。还有一个坑点是,题目中说每个用户的训练时长不得超过2个小时,我以为是限定的输入条件呢。。。。结果是需要在代码中加以逻辑判断,如果超过2小时,需要手动改成2小时。。。改完之后才过了一直都过不去的测试点4。
思路
用了一个大循环模拟时间的走动,若某用户在当前时刻到达则将该用户加入等待队列中。如果等待队列不为空,则去遍历所有的桌子。
- 首先遍历所有的VIP桌子,寻找在当前时刻是否有空闲的,如果有则在队列中查找VIP用户,如果队列中没有VIP用户,则跳出遍历循环。如果有VIP用户,则将该VIP用户分配到此VIP桌子。
- 从上个遍历结束之后此时的条件便是:1. 当前队列中并没有任何的VIP用户,2. 当前所有的VIP桌子都已经占用了。上述俩个条件下,将队列中所有等待者都将当作普通用户处理,也即遍历所有桌子,此时不分VIP桌子和普通桌子。但凡有桌子空闲,就将其分配给等待队列中的第一个用户。
AC代码
#include <iostream>
#include <cmath>
#include <string>
#include <algorithm>
#include <list>
using namespace std;
typedef struct table {//桌子
bool vip;
int sum;
int endtime;
}table;
typedef struct customer {//用户
bool vip;
int atime;//秒级别的到达时间
int time;//训练时长
int wtime;//等待时间
string as, ss;//到达时间和服务时间
}customer;
customer c[10000];
bool compare(customer c1, customer c2) {
return c1.atime < c2.atime;
}
bool compare1(customer c1, customer c2) {
if (c1.ss != c2.ss) {
return c1.ss < c2.ss;
}
else {
return c1.wtime < c2.wtime;
}
}
int getTime(string s, string e) {//计算俩时间的时间间隔,以秒为单位
if (s > e) {
return -1;
}
int t1[3], t2[3];
for (int i = 0; i < 8; i += 3) {
t1[i / 3] = (s[i] - '0') * 10 + (s[i + 1] - '0');
t2[i / 3] = (e[i] - '0') * 10 + (e[i + 1] - '0');
}
int sum = 0;
if (t1[0] < t2[0]) {
sum += (60 - t1[2] + (60 - t1[1] - 1) * 60);
sum += (t2[0] - t1[0] - 1) * 3600;
sum += (t2[1] * 60 + t2[2]);
}
else {
if (t1[1] < t2[1]) {
sum += (60 - t1[2] + (t2[1] - t1[1] - 1) * 60);
sum += t2[2];
}
else {
sum += (t2[2] - t1[2]);
}
}
return sum;
}
string getT(int t) {//将离8:00:00时刻的时间间隔转化为字符串格式的时间
string a = "";
int h = t / 3600 + 8;
t = t % 3600;
int m = t / 60;
t = t % 60;
string hs = to_string(h);
string ms = to_string(m);
string ts = to_string(t);
if (hs.length() == 1) {
a += "0";
}
a += hs + ":";
if (ms.length() == 1) {
a += "0";
}
a += ms + ":";
if (ts.length() == 1) {
a += "0";
}
a += ts;
return a;
}
int main() {
table t[100];
int vip[100];
int ord[100];
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> c[i].as >> c[i].time >> c[i].vip;
c[i].atime = getTime("08:00:00", c[i].as);
c[i].wtime = -1;
}
sort(c, c + n, compare);
int k, m;
cin >> k >> m;
for (int i = 0; i < k; i++) {
t[i].endtime = 0;
t[i].sum = 0;
t[i].vip = false;
}
for (int i = 0; i < m; i++) {
int tmp;
cin >> tmp;
t[tmp - 1].vip = true;
}
int site = 0;
list<int> q;
for (int i = 0; i < 46800; i++) {//模拟时间的走动
if (site < n) {
if (i == c[site].atime) {//有用户在当前时刻到达
q.push_back(site);
site++;
}
}
for (int j = 0; j < k; j++) {//优先vip
if (q.empty())break;
if (t[j].vip && t[j].endtime <= i) {
int flag = 0;
if (!q.empty()) {
list<int>::iterator it;
for (it = q.begin(); it != q.end(); *it++) {
if (c[(*it)].vip) {
flag = 1;
t[j].endtime += (c[(*it)].time * 60 + (c[(*it)].atime > t[j].endtime ? (c[(*it)].atime - t[j].endtime) : 0));
t[j].sum++;
c[(*it)].wtime = i - c[(*it)].atime;
q.remove((*it)); break;
}
}
}
if (q.empty() || flag == 0)break;
}
}
for (int j = 0; j < k; j++) {//要么没有vip用户,要么vip桌子全满了
if (q.empty())break;
if (t[j].endtime <= i) {
if (!q.empty()) {
t[j].endtime += (c[q.front()].time * 60 + (c[q.front()].atime > t[j].endtime ? (c[q.front()].atime - t[j].endtime) : 0));
t[j].sum++;
c[q.front()].wtime = i - c[q.front()].atime;
q.remove(q.front());
}
}
}
}
for (int i = 0; i < n; i++) {
if (c[i].wtime != -1) {
c[i].ss = getT(c[i].atime + c[i].wtime);
}
else {
c[i].ss = "21:00:01";
}
}
sort(c, c + n, compare1);
for (int i = 0; i < n; i++) {
if (c[i].wtime != -1) {
double f = (double)c[i].wtime / (double)60;
cout << c[i].as << " " << c[i].ss << " " << round(f) << endl;
}
}
for (int i = 0; i < k; i++) {
cout << t[i].sum;
if (i < k - 1) {
cout << " ";
}
}
system("pause");
}