乒乒乓乓:这点小事儿,算什么?

开发 前端
对于任意一对球员,当他们到达时如果有多个球台可用,那么他们就会被安排到编号较小的那个球台上打球。

[[418167]]

本文转载自微信公众号「Piper蛋窝」,作者Piper蛋。转载本文请联系Piper蛋窝公众号。

一道 PAT 原题,被称为「PAT史上最麻烦题目」:

  • PAT 原题英文链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805472333250560
  • AcWing 翻译:https://www.acwing.com/problem/content/1505/

原题

一个乒乓球俱乐部共有K张乒乓球台,编号为1~K 。

对于任意一对球员,当他们到达时如果有多个球台可用,那么他们就会被安排到编号较小的那个球台上打球。

如果所有球台都被占用了,他们就只能排队等待了。

假设每对球员最多只允许打两小时球

你需要计算每个排队等候的人的等待时间以及每个球台当天有多少对球员在上面打球。

另外,让这个事情变得复杂的是,俱乐部为 VIP 球员保留了一些球台。

当一个 VIP 球台空出时,等待队伍中的第一对 VIP 球员将优先使用这个球台。

如果此时等待队伍中没有 VIP,则排在等待队伍的第一对球员可以使用这个球台。

另一方面,当轮到一对 VIP 球员打球时,如果没有 VIP 球台可用,那么他们将被视作普通球员处理。

补充:

1、当等待队伍中有 VIP 球员并且有空闲 VIP 球台时,必须优先分配 VIP 球员,并且必须分配他们 VIP 球台(优先分配编号较小的),直至 VIP 用户或 VIP 球台分配完为止。

2、期望打球时间超过两小时的,只能允许打两小时。

3、当多对球员的开始打球时间相同时,先输出到达时间早的球员的信息。

4、当等待球员中没有 VIP 时,VIP 球台视作普通球台处理,当可用球台中没有 VIP 球台时,VIP 球员视作普通球员处理。

输入格式

第一行包含整数N,表示共有N对球员。

接下来N行,每行包含两个时间以及一个 VIP 标识,HH:MM:SS----到达时间,p----打球时间(单位:分钟),tag----如果是 ,说明这是一对 VIP,如果是 ,说明不是 VIP。

保证到达时间在 08:00:00 至 21:00:00 之间,这是俱乐部的营业时间。

保证每对球员的到达时间都不相同。

再一行包含两个整数K和M,表示球台数量以及 VIP 球台数量。

最后一行包含M个整数,表示 VIP 球台的编号。

输出格式

首先输出每对球员的到达时间,开始打球时间,等待时间。

每对球员的信息占一行,按开始打球时间从早到晚的顺序依次输出。

等待时间必须四舍五入为整数分钟。

如果一对球员在 21:00:00 之前(不包括 21:00:00)不能得到一张球台,那么无需输出他们的信息。

再输出一行,K个整数,表示每个球台服务的球员对数。

数据范围

输入样例:

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

输出样例:

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

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 privilege 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.

思路:

  • 把 Player 和 Table 分别放到四个优先队列里面
    • VIP Player
    • VIP Table
    • normal Player
    • normal Table
  • 把所有 Player 放入相应的优先队列,被分配了就把 Player 弹出来,被分配到的 Table 也弹出来,更新结束时间,再放入 Table 对应的队列
  • 关键时间点全靠堆顶输出
  • 因此退出循环的依据有两个:Player 空了,或者没有 Table 在 21:00 前结束
  • 桌子分配原则:
    • 如果轮到 VIP Player 并且 VIP Table 有空缺,则分配;
    • 如果轮到 normal Player 并且只有 VIP Table 有空缺,分配;
    • 如果轮到 VIP Player 并且只有 VIP Table 有空缺,分配;
    • 其他情况分配 normal Player

注意事项:

  • 往各个优先队列输入 INF 的时间原始,且保证其永远不会到达堆顶,这样不用判断是不是空节点
  • 每次四个优先队列都出队堆顶,方便书写
  • 对于每个玩家关键时间点 cur_time ,如果有桌子的 end_time 比这个小,则更新 end_time 为这个 cur_time ,防止后面漏判空余桌子
  1. #include <iostream> 
  2. #include <cstring> 
  3. #include <algorithm> 
  4. #include <queue> 
  5. #include <vector> 
  6. #include <cmath> 
  7.  
  8. using namespace std; 
  9.  
  10. const int N = 1e4 + 10, M = 1e2 + 10, INF = 2e9; 
  11. int n, k, m; 
  12.  
  13. struct Player 
  14.     int arrive_time, serve_time; 
  15.     int start_time, waiting_time; 
  16.      
  17.     // 给 sort 排 
  18.     const bool operator< (const Player& t) const 
  19.     { 
  20.         if (start_time != t.start_time) return start_time < t.start_time; 
  21.         return arrive_time < t.arrive_time; 
  22.     } 
  23.      
  24.     // 给 priority_queue 排 
  25.     const bool operator> (const Player& t) const 
  26.     { 
  27.         return arrive_time > t.arrive_time; 
  28.     } 
  29. }; 
  30.  
  31. struct Table 
  32.     int id; 
  33.     int end_time; 
  34.      
  35.     const bool operator> (const Table& t) const 
  36.     { 
  37.         if (end_time != t.end_time) return end_time > t.end_time; 
  38.         return id > t.id; 
  39.     } 
  40. }; 
  41.  
  42. bool is_vip_table[M]; 
  43. int table_count[M]; 
  44.  
  45. // 最终输出的玩家及顺序 
  46. vector<Player> players; 
  47.  
  48. // 注意 `&` 很重要 
  49. void assign(priority_queue<Player, vector<Player>, greater<Player>>& ps, 
  50.             priority_queue<Table, vector<Table>, greater<Table>>& ts) 
  51.     auto p = ps.top(); 
  52.     ps.pop(); 
  53.     auto t = ts.top(); 
  54.     ts.pop(); 
  55.     int start_time = t.end_time; 
  56.     int end_time = start_time + p.serve_time; 
  57.     ts.push({t.id, end_time}); 
  58.     table_count[t.id] ++; 
  59.     p.start_time = start_time; 
  60.     p.waiting_time = round((start_time - p.arrive_time) / 60.0); 
  61.     players.push_back(p); 
  62.  
  63. string time_to_string(int sec) 
  64.     char str[20]; 
  65.     sprintf(str, "%02d:%02d:%02d", sec / 3600, sec % 3600 / 60, sec % 60); 
  66.     return str; 
  67.  
  68. int main() 
  69.     // 输入玩家 
  70.     priority_queue<Player, vector<Player>, greater<Player>> normal_players; 
  71.     priority_queue<Player, vector<Player>, greater<Player>> vip_players; 
  72.      
  73.     normal_players.push({INF}); 
  74.     vip_players.push({INF}); 
  75.  
  76.     cin >> n; 
  77.     for (int i = 0; i < n; i ++ ) 
  78.     { 
  79.         int hourminute, sec; 
  80.         int serve_time, is_vip; 
  81.         scanf("%d:%d:%d %d %d", &hour, &minute, &sec, &serve_time, &is_vip); 
  82.         sec = hour * 3600 + minute * 60 + sec; 
  83.         serve_time = min(serve_time * 60, 7200); 
  84.         if (is_vip) vip_players.push({sec, serve_time}); 
  85.         else normal_players.push({sec, serve_time}); 
  86.     } 
  87.      
  88.     // 输入桌子 
  89.     priority_queue<Table, vector<Table>, greater<Table>> normal_tables; 
  90.     priority_queue<Table, vector<Table>, greater<Table>> vip_tables; 
  91.      
  92.     normal_tables.push({-1, INF}); 
  93.     vip_tables.push({-1, INF}); 
  94.      
  95.     cin >> k >> m; 
  96.     for (int i = 0; i < m; ++ i) 
  97.     { 
  98.         int id; 
  99.         cin >> id; 
  100.         is_vip_table[id] = true
  101.     } 
  102.      
  103.     for (int i = 1; i <= k; i ++ ) 
  104.     { 
  105.         if (is_vip_table[i]) vip_tables.push({i, 8 * 3600}); 
  106.         else normal_tables.push({i, 8 * 3600}); 
  107.     } 
  108.      
  109.     // 开始分配 
  110.     while (normal_players.size() > 1 || vip_players.size() > 1) 
  111.     { 
  112.         auto np = normal_players.top(); 
  113.         auto vp = vip_players.top(); 
  114.          
  115.         int cur_time = min(np.arrive_time, vp.arrive_time); 
  116.          
  117.         while (normal_tables.top().end_time < cur_time) 
  118.         { 
  119.             auto t = normal_tables.top(); 
  120.             normal_tables.pop(); 
  121.             t.end_time = cur_time; 
  122.             normal_tables.push(t); 
  123.         } 
  124.          
  125.         while (vip_tables.top().end_time < cur_time) 
  126.         { 
  127.             auto t = vip_tables.top(); 
  128.             vip_tables.pop(); 
  129.             t.end_time = cur_time; 
  130.             vip_tables.push(t); 
  131.         } 
  132.          
  133.         auto nt = normal_tables.top(); 
  134.         auto vt = vip_tables.top(); 
  135.         int end_time = min(nt.end_time, vt.end_time); 
  136.  
  137.         if (end_time >= 21 * 3600) break; 
  138.  
  139.         if (vp.arrive_time <= end_time && vt.end_time == end_time) assign(vip_players, vip_tables); 
  140.         else if (np.arrive_time < vp.arrive_time) 
  141.         { 
  142.             if (nt > vt) assign(normal_players, vip_tables); 
  143.             else assign(normal_players, normal_tables); 
  144.         } 
  145.         else 
  146.         { 
  147.             if (nt > vt) assign(vip_players, vip_tables); 
  148.             else assign(vip_players, normal_tables); 
  149.         } 
  150.     } 
  151.      
  152.     sort(players.begin(), players.end()); 
  153.      
  154.     for (auto p: players) 
  155.     { 
  156.         cout << time_to_string(p.arrive_time) << " " << time_to_string(p.start_time) << " " << p.waiting_time << endl; 
  157.     } 
  158.  
  159.     for (int i = 1; i <= k; i ++ ) 
  160.     { 
  161.         cout << table_count[i]; 
  162.         if (i + 1 <= k) cout << " "
  163.         else cout << endl; 
  164.     } 

 

 

责任编辑:武晓燕 来源: Piper蛋窝
相关推荐

2018-10-30 15:40:15

MySQL缓存Tomcat

2018-10-29 16:15:09

MySQL数据库缓存

2010-07-27 16:21:25

程序员

2009-12-21 17:00:22

Linux操作系统

2017-12-13 15:30:55

2022-12-28 10:13:40

云计算云原生

2013-06-04 09:49:48

游戏设计

2017-08-10 16:36:43

Android导航标签

2019-03-25 21:11:35

华为

2013-06-03 09:16:26

云计算

2013-04-17 10:12:43

数据分析大数据

2023-02-28 08:29:01

MySQL主键索引

2015-07-22 11:35:55

MongoDB数据暴露数据库安全

2021-03-13 11:23:51

源码逻辑框架

2015-09-09 14:47:39

魅族

2015-03-25 10:56:10

2022-09-09 19:01:02

接口Reader​Spark

2012-08-13 13:40:30

WebGL

2023-05-06 10:28:14

云计算边缘计算

2011-06-30 11:23:32

Python
点赞
收藏

51CTO技术栈公众号