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桌,普通用户也可以使用VIP桌。
这类题目需要处理桌子的空闲与用户的到达、服务时间之间的关系,需要有一个较好的思路,否则很容易混乱。
一个比较好的思路是为每个桌子设定空闲时间,首先全部初始化为上午8:00,当处理一个人时,首先从桌子列表最前面取到桌子,然后根据自己的到达时间和桌子的空闲时间即可计算出桌子的新空闲时间、用户的等待时间和服务时间(有可能到关门时达不到预期服务时间)。
这道题麻烦在VIP上,如果有VIP用户,他们可以“插队”,要处理这些用户,就会让问题变得复杂,不能简单的取出第一个未服务用户和第一个桌子,而是要考虑有VIP用户和VIP桌子的情况,这里有两种优秀的解法:
①类似归并排序的思想,维护普通用户和VIP用户两个队列。
②仅使用一个队列,先考虑VIP情况,没有VIP被处理则按照正常情况处理,算法来自sunbaigui。
我完整的参考了sunbaigui的解法,他的解法非常巧妙,下面罗列一下关键点:
①对用户排序后从前到后处理,初始化服务开始时间为INF,这样当处理完一个人时,他的服务时间不再是INF,由此判断是否处理完毕,不必另设标志。
②不对桌子排序,而是找到所有桌子中空闲时间最早的,从桌子列表从前到后筛选,这样就保证了按照编号的顺序,十分巧妙。
③根据②中找到的最早空闲时间,找出所有符合的桌子和用户,分别存储一个新的容器,后面就针对这两个新的容器处理。
④分情况讨论,单人单桌、多人单桌、多人多桌,在这三种情况下分别判断是否有VIP被服务。
⑤如果④中没有VIP被服务,则取出新容器中第一个用户和第一个桌子,正常处理。
下面的代码来自sunbaigui,我在他代码的基础上加了些注释,方便理解。
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<algorithm>
#include<string>
#include<string.h>
#include<stdio.h> using namespace std; typedef struct Node
{
int arrive, process, tag;
int serve, wait; // serve和wait分别代表服务开始时间和等待时间,将serve初始化为INF,从而区分有没有被服务
}Node;
typedef struct Table
{
int tag;
int freeTime, num; // 每个桌子记录自己的空闲时间和服务数,全部初始化为上午8:00,这样可以迭代着处理
}Table;
bool CmpArrive(Node a, Node b) // 用于对用户的到达时间升序排序
{
return a.arrive < b.arrive;
}
bool CmpServe(Node a, Node b) // 对用户按照时间顺序排列,优先按照服务时间排序,如果服务同时开始(多个空桌),按照到达时间升序
{
if(a.serve == b.serve)
return a.arrive < b.arrive;
else return a.serve < b.serve;
}
#define INF 0x6FFFFFFF vector<Node> user;
vector<Table> table;
void UpdateInfo(int userID, int tableID)
{
user[userID].serve = max(user[userID].arrive, table[tableID].freeTime);
user[userID].wait = user[userID].serve-user[userID].arrive;
table[tableID].num++;
table[tableID].freeTime = user[userID].serve+min(user[userID].process, 7200); // 最长服务时间为2小时
}
int main()
{
//input
int n;
scanf("%d",&n); user.resize(n);
for(int i = 0; i < n; ++i)
{
int h, m, s;
scanf("%d:%d:%d %d%d",&h,&m,&s,&user[i].process,&user[i].tag);
user[i].arrive = h*3600+m*60+s;
user[i].process *= 60;
user[i].serve = INF; user[i].wait = INF; // 初始化为INF,INF就代表未被处理
}
int k, m;
scanf("%d%d",&k,&m); table.resize(k);
for(int i = 0; i < k; ++i)
table[i].freeTime = 8*3600, table[i].tag = 0, table[i].num = 0; // 所有桌子从上午8:00开始可用
for(int i = 0; i < m; ++i)
{
int c;
scanf("%d",&c); c--;
table[c].tag = 1;
}
//process
sort(user.begin(), user.end(), CmpArrive); // 按照到达时间升序排列,符合排队规则
//visited.assign(n, false);
for(int i = 0; i < n; ++i)
{
if(user[i].serve != INF) continue; // server时间初始化为INF,不为INF的已经服务完毕。
int minFreeTime = INF;
for(int j = 0; j < k; ++j)
minFreeTime = min(minFreeTime, table[j].freeTime); // 找出最早空闲的桌子
int timePoint = max(user[i].arrive, minFreeTime); // 根据队头用户确定当前最早服务时间点
if(timePoint >= 21*3600) break; // 判断是否超过营业时间
vector<int> userList;
vector<int> tableList;
for(int j = i; j < n; ++j) // 根据最早服务时间点找到所有可能被服务的人,是为了处理有VIP优先去VIP桌的情况。
if(user[j].serve == INF && user[j].arrive <= timePoint) userList.push_back(j);
for(int j = 0; j < k; ++j) // 找出所有在时间点之前空闲的桌子,因为可能用户到达晚,因此会有多个桌子空闲
if(table[j].freeTime <= timePoint) tableList.push_back(j); bool flag = false; // 判断是否处理了一个服务
// 首先特殊处理VIP,如果没有VIP被处理则处理一个普通用户,每次只处理一个
if(userList.size() == 1 && tableList.size() > 1) // 单个用户多个桌子,用户为VIP则去找编号最小的VIP桌
{
if(user[userList[0]].tag == 1)
{
for(int j = 0; j < tableList.size(); ++j)
{
if(table[tableList[j]].tag == 1)
{
flag = true;
UpdateInfo(userList[0], tableList[j]);
break;
}
}
}
}
else if(tableList.size() == 1 && userList.size() > 1) // 多人单桌情况,如果为VIP桌找多人中最先到达的VIP为其服务
{
if(table[tableList[0]].tag == 1)
{
for(int j = 0; j < userList.size(); ++j)
{
if(user[userList[j]].tag == 1)
{
flag = true;
UpdateInfo(userList[j], tableList[0]);
break;
}
}
}
}
else if(tableList.size() > 1 && userList.size() > 1) // 多人多桌情况,先找桌子中的VIP桌,有则找用户中最先到达的VIP
{
for(int t = 0; t < tableList.size(); ++t)
{
if(table[tableList[t]].tag == 1)
{
for(int u = 0; u < userList.size(); ++u)
{
if(user[userList[u]].tag == 1)
{
flag = true;
UpdateInfo(userList[u], tableList[t]);
break;
}
}
}
}
}
if(!flag) UpdateInfo(userList[0], tableList[0]); // 如果没有VIP被处理,则按照正常情况处理。
--i;
}
//output
sort(user.begin(), user.end(), CmpServe);
for(int i = 0; i < n; ++i)
{
if(user[i].serve >= 21*3600) break;
int h1, m1, s1, h2, m2, s2;
int t = user[i].arrive;
h1 = t/3600; t %= 3600;
m1 = t/60; t %= 60;
s1 = t;
t = user[i].serve;
h2 = t/3600; t %= 3600;
m2 = t/60; t %= 60;
s2 = t;
// 注意对等待时间的四舍五入为超过30秒算作一分钟
printf("%02d:%02d:%02d %02d:%02d:%02d %d\n", h1, m1, s1, h2, m2, s2, (user[i].wait+30)/60);
}
for(int i = 0; i < k; ++i)
{
if(i != k-1)
printf("%d ",table[i].num);
else printf("%d\n",table[i].num);
}
return 0;
}
1026. Table Tennis (30)的更多相关文章
- PAT 甲级 1026 Table Tennis (30 分)(坑点很多,逻辑较复杂,做了1天)
1026 Table Tennis (30 分) A table tennis club has N tables available to the public. The tables are ...
- 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 a ...
- 1026 Table Tennis (30)(30 分)
A table tennis club has N tables available to the public. The tables are numbered from 1 to N. For a ...
- 1026 Table Tennis (30分)
A table tennis club has N tables available to the public. The tables are numbered from 1 to N. For a ...
- 1026 Table Tennis (30分) 难度不高 + 逻辑复杂 +细节繁琐
题目 A table tennis club has N tables available to the public. The tables are numbered from 1 to N. Fo ...
- 【PAT甲级】1026 Table Tennis (30 分)(结构体排序,trick较多)
题意: 输入一个正整数N(<=10000),表示客户(对)的大小,接着输入N行数据,每行包括一对顾客到场的时间,想要玩的时间,以及是否是VIP客户.接下来输入两个正整数K,M(K<=100 ...
- PAT (Advanced Level) 1026. Table Tennis (30)
情况比较多的模拟题. 交了50发的样子才AC......AC之后我的天空星星都亮了. #include<iostream> #include<cstring> #include ...
- PAT 1026 Table Tennis[比较难]
1026 Table Tennis (30)(30 分) A table tennis club has N tables available to the public. The tables ar ...
- PAT 甲级 1026 Table Tennis(模拟)
1026. Table Tennis (30) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue A table ...
随机推荐
- BZOJ4424: Cf19E Fairy
树上差分的代码很简洁,dfs+差分即可 这题很多坑点啊,比如重边自环好坑 #include<cstdio> #include<cstdlib> #include<algo ...
- UVA - 11235:Frequent values
非常优美的RMQ问题,可以运到桶的思想 #include<cstdio> #include<cstdlib> #include<algorithm> #includ ...
- 细胞(cell) 矩阵快速幂
题目描述小 X 在上完生物课后对细胞的分裂产生了浓厚的兴趣.于是他决定做实验并观察细胞分裂的规律.他选取了一种特别的细胞,每天每个该细胞可以分裂出 x 1 个新的细胞.小 X 决定第 i 天向培养皿中 ...
- bzoj 4974: 字符串大师
Description 一个串T是S的循环节,当且仅当存在正整数k,使得S是T^k(即T重复k次)的前缀,比如abcd是abcdabcdab的循环节 .给定一个长度为n的仅由小写字符构成的字符串S,请 ...
- [BZOJ]1079 着色方案(SCOI2008)
相邻色块不同的着色方案,似乎这道题已经见过3个版本了. Description 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块.所有油漆刚好足够 ...
- bzoj3685普通van Emde Boas树 线段树
3685: 普通van Emde Boas树 Time Limit: 9 Sec Memory Limit: 128 MBSubmit: 1932 Solved: 626[Submit][Stat ...
- widows下的进程与服务
进程: 当程序卡死的时候,我们可以直接通过任务管理器来关闭进程. 服务: 在这个界面,我们可以选择启动或者关闭相关服务,还可以选择服务是否自动启动. 以关闭MySQL自启动服务为例:https://j ...
- 利用生产者消费者模型和MQ模型写一个自己的日志系统-并发设计里一定会用到的手段
一:前言 写这个程序主要是用来理解生产者消费者模型,以及通过这个Demo来理解Redis的单线程取原子任务是怎么实现的和巩固一下并发相关的知识:这个虽然是个Demo,但是只要稍加改下Appender部 ...
- Window下使用ftp命令往Linux中发送文件
操作步骤:首先,切换到文件目录1.ftp ip地址2.连接成功后,输入正确的用户名和密码.3.binary(表示以二进制的格式传送)4.put/get 文件名(或文件的绝对路径) 退出:bye
- python笔记十五(面向对象及其特性)
一.面向对象: class(类):一类拥有共同属性对象的抽象:定义了这些对象的属性和方法object(对象):是一个类实例化后的实例,类必须经过实例化才可以在程序中调用: 由于之前学习过java,对类 ...