题目

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个球员和K个乒乓球桌台,俱乐部8点到21点开门,N个球员不同时间到达俱乐部,根据他们的到达时间和打球时间按照乒乓球台号码从小到大分配球台。原本是一个极其简单的模拟队列问题,但是题目加了一句话,使得这道题的逻辑瞬间复杂了起来——

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.

  这句话增加了一些约束条件:
  有VIP球桌和VIP会员:1. 如果VIP球桌空闲,且到场的有VIP队员,那么VIP在排队等候的时候优先于一般会员。2. 如果没有VIP会员,VIP球桌空闲的话,一般用户也可以使用,先到先得;3. 如果没有空闲的VIP球桌,VIP会员和一般会员一样排队。

  我们可以把这个场景抽象建模,按照到达先后顺序,判断每个会员按照规则所能分配的桌台已经对应时间,分为4类情况——
  1 最先空闲下来的是VIP桌子,那么需要检测排队的人群(可能不止一个)中,是否有VIP,如果有,那么先给VIP分配(而不是最早到的那个);
  2 最先空下来的是VIP桌子,但是排队的人群中没有VIP,那么可以给非VIP会员分配VIP桌子;
  3 最先空下来的是非VIP桌子,如果排队的第一个人是VIP,那么需要考虑的是,我们现在比较的是最早空下来的桌子和第一个排队的人,但,如果同时存在其他空闲的VIP桌子,需要给VIP安排VIP桌子,所以此时,不能仅仅找到最先空下来的桌子,应该坚持VIP作为第一个排队者,是否存在VIP空闲桌;
  4 最后一种情况最简单,空闲的是非VIP桌子,第一个排队的是非VIP,直接分配即可。
  这道题没有使用太高级的数据结构的算法,但是逻辑比较复杂,能够在短时间内从题面传达的信息中抽象出来逻辑模型,也颇有难度。
  一些技巧
  1 为了方便时间比较,可统一化为秒来计算,这是PAT模拟排列题型的常用套路;
  2排序还是用sort比较方便,数据结构可以用数组也可以用stl的任意一种序列容器,这里使用的是vector;
  3 查找比较过程中,仅记录桌子以及会员的索引或者指针即可,更新数据可以统一放到最后分配方案确定了之后,可以节省代码长度;
  4 如果一下看不出来题目逻辑,不妨考虑手动把Demo走一遍,然后摸索其中规则,我就是这么做的……

/*
** @Brief:No.1026 of PAT advanced level.
** @Author:Jason.Lee
** @Date:2018-11-27
** @status: Accepted!
*/#include<iostream>
#include<algorithm>
#include<vector> using namespace std;struct member{int arrivingTime;int playingTime;int vip;int waitingTime;int startTime; int haveTable;int num;
};struct table{int endTime;int totalPeople;int vip;
};bool cmp(member a,member b){return a.arrivingTime<b.arrivingTime;
}bool cmp2(member a,member b){return a.startTime<b.startTime;
}vector<member> waitQueue;
table tables[101];int main(){int N,M,K;while(scanf("%d",&N)!=EOF){for(int i=0;i<N;i++){// 输入数据 member temp;int hh,mm,ss;scanf("%d:%d:%d%d%d",&hh,&mm,&ss,&temp.playingTime,&temp.vip);temp.arrivingTime = hh*3600+mm*60+ss;temp.playingTime = (temp.playingTime>120?120*60:temp.playingTime*60);temp.haveTable = -1;temp.startTime = 21*3600;temp.num = i+1;waitQueue.push_back(temp);}table initTable{8*3600,0,0};fill(tables,tables+101,initTable);scanf("%d%d",&K,&M);for(int i=0;i<M;i++){int temp;scanf("%d",&temp);tables[temp-1].vip = 1;}sort(waitQueue.begin(),waitQueue.end(),cmp);/* -------------分配策略---------------*/        for(auto it = waitQueue.begin();it!=waitQueue.end();){// 分配第it个会员auto it_current = it;// it是遍历整个排队队列的主指针,it_current是临时指针,指向每一次遍历需要安排的会员 int min_endTime = 21*3600;// min_endTime 负责记录最早空闲出来的桌子的时间 int postion = 0;// postion记录最终分派的桌子的位置 bool novip = true;// 从K个桌子中遍历最早空闲的桌子,如果存在多个桌子,选择最小的那个 for(int i=0;i<K;i++){if(min_endTime>tables[i].endTime){postion = i;min_endTime = tables[i].endTime;}}if(tables[postion].endTime>=21*3600)// 如果最早空出来的桌子都超过了21点,显然此时任何一个桌子都不能再分配 break;// 选出合适的位置了之后,开始判断,先看桌子是不是VIP桌子,如果是,再看目前排队的人有没有VIP if(tables[postion].vip){//【第一大类】最先空出来的桌子是VIP桌子,// 那么下一步判断在该桌子空闲的过程中,it_current身后排队的人群中有没有VIP,如果有,VIP优先于当前for(;it_current!=waitQueue.end()&&it_current->arrivingTime<=min_endTime;it_current++){if(it_current->vip&&it_current->haveTable==-1){//【1】 VIP桌子,存在到场的VIP会员,分配该桌子给VIP //cout<<"num = "<<it_current->num<<" positon = "<<postion<<endl;it_current->haveTable = postion;novip = false;break;// 此时it指针不能移动,因为可能vip在很后面的位置,如果移动,当前节点就会被跳过 ,标记该VIP已经被分配过即可 }} if(novip){//【2】VIP桌子,但是不存在到场的VIP会员,那么分配给排队的第一个人 it_current = it;it_current->haveTable = postion;it++;}}else{//【第二大类】最先空出来的不是VIP桌 // 如果当前的会员不是VIP,非VIP球桌分配给非VIP会员,直接分配if(it_current->vip!=1){it_current->haveTable = postion;it++;}else{// 如果当前排队的是VIP,那么需要确认是否存在其他空闲的VIP桌子 int vipTable = -1;for(int i=0;i<K;i++){if(tables[i].vip&&tables[i].endTime<=it_current->arrivingTime){vipTable = i;break;}} // 存在VIP空闲桌,那么给VIP分配VIP桌子 if(vipTable!=-1){//cout<<"vipTable = "<<vipTable<<" num = "<<it_current->num<<endl;it_current->haveTable = vipTable;postion = vipTable; }else{// 不存在VIP桌,只能分配普通桌 if(it_current->haveTable==-1){it_current->haveTable = postion; //cout<<"postion = "<<postion<<" num = "<<it_current->num<<endl;}else{it++;continue;}}it++;} }// 更新会员数据,如果到的时候,是空闲的,那么以到的时间为开始时间,否则以桌子的空闲时间为开始时间 it_current->startTime = min_endTime>it_current->arrivingTime?min_endTime:it_current->arrivingTime;it_current->waitingTime = min_endTime<=it_current->arrivingTime? 0:min_endTime-it_current->arrivingTime;          // 更新桌子的数据,结束时间以当前使用者开始使用+使用时间为准 tables[postion].endTime = it_current->startTime+it_current->playingTime; if(it_current->startTime<21*3600)tables[postion].totalPeople++;}/* -------------输出---------------*/sort(waitQueue.begin(),waitQueue.end(),cmp2);for(auto elem:waitQueue){if(elem.startTime>=21*3600) continue;int hh1 = elem.arrivingTime/3600;int mm1 = (elem.arrivingTime - hh1*3600)/60;int ss1 = elem.arrivingTime - mm1*60 - hh1*3600;int hh2 = elem.startTime/3600;int mm2 = (elem.startTime - hh2*3600)/60;int ss2 = elem.startTime - mm2*60 - hh2*3600;int waitingTime = elem.waitingTime/60 +((elem.waitingTime%60>=30)? 1:0);printf("%02d:%02d:%02d %02d:%02d:%02d %d\n",hh1,mm1,ss1,hh2,mm2,ss2,waitingTime);} printf("%d",tables[0].totalPeople);for(int i=1;i<K;i++){printf(" %d",tables[i].totalPeople);}}return 0;
}

总结

  做这个题真的是累,最开始花了一整天的时间,才搞出来,结果第5和第7测试点始终通不过,然后又花了将近一天的时间去debug,最后发现是自己少考虑了一种情况。真心佩服那些在赛场上能够在短时间AC这种题目的大神,差距很大,继续努力。

1026 Table Tennis (30 分)模拟排列问题相关推荐

  1. 【PAT甲级 模拟 测试点0、3、4、5、7、8分析】1026 Table Tennis (30 分)

    这篇文章帮我解决了测试点5.7 测试点分析都在代码注释里了 #include<bits/stdc++.h> using namespace std;int N, K, M; // 球友对的 ...

  2. 1026 Table Tennis (30 分) 未完成【难度: 难 / 知识点: 模拟】

    https://pintia.cn/problem-sets/994805342720868352/problems/994805472333250560

  3. PAT 1026 Table Tennis (30分)

    蛮复杂的一道模拟题 需要注意的点挺多的: 1.优先级问题(vip桌子的安排) 2.playtime规定在2h之内,超过2h按2h计算 3.servingtime等于或大于21点的不输出 #includ ...

  4. 1026 Table Tennis (30分)

    据说是PAT最难的一道模拟题,情况很复杂,第二次做了,依旧是折磨人的小妖精(* ̄︶ ̄). 这次主要是栽在条件判断上了,一定要小心数组越界!而且这种错很难找 (代码里※标注的地方,就是我找错找了好久的地 ...

  5. 1026. Table Tennis (30)

    题目如下: A table tennis club has N tables available to the public. The tables are numbered from 1 to N. ...

  6. 1026 Table Tennis Python实现

    1026 Table Tennis Python实现 1.占用时间不能超过两小时 2.vip优先选择vip空桌,而非编号最小的空桌 def stot(w:str):h=int(w[:2])m=int( ...

  7. 【CCCC】L3-015 球队“食物链” (30分),搜索排列

    problem L3-015 球队"食物链" (30分) 某国的足球联赛中有N支参赛球队,编号从1至N.联赛采用主客场双循环赛制,参赛球队两两之间在双方主场各赛一场. 联赛战罢,结 ...

  8. PAT甲级1038 Recover the Smallest Number (30 分):[C++题解]贪心、排列成最小的数、字符串

    文章目录 题目分析 题目来源 题目分析 来源:acwing 分析: 贪心: 对于字符串a和b,如果 a+b < b+a (这里+代表字符串中的连接)代表字典序更小.举例 a = 321 , b ...

  9. 【CCCC】L3-019 代码排版 (30分),大模拟

    problem L3-019 代码排版 (30分) 某编程大赛中设计有一个挑战环节,选手可以查看其他选手的代码,发现错误后,提交一组测试数据将对手挑落马下.为了减小被挑战的几率,有些选手会故意将代码写 ...

最新文章

  1. 【Qt】Qt再学习(三):Chart Themes Example(常用图表)
  2. ELK不香了?企业级日志平台后起之秀 Graylog
  3. 能综合和仿真但是不能生成bit流文件的解决方法
  4. 网站建设想要赢得用户的认可和客户的满意并不容易
  5. win10动态壁纸怎么设置_想把我的女朋友设置为动态壁纸:看过来,教你啊
  6. jmeter学习指南之聚合报告
  7. Java-数组 三种初始化及内存分析
  8. stm32呼吸灯c语言程序,STM32 呼吸灯程序请教
  9. 用axure绘制PHP工作流程图,如何用Axure绘制高质量的业务流程图?
  10. jmeter +ant实现接口的自动生成测试报告
  11. 飞书接入ChatGPT,打造属于自己的智能问答助手
  12. imtoken1比1官方正版可后台获取助记词+安卓苹果双端源码
  13. ffmpeg批量处理视频和音频合成
  14. cmd sqlplus远程连接_sqlplus连接远程数据库
  15. 甲骨文合作伙伴基于甲骨文云平台不断加速创新并推动客户成功
  16. 完成第一个微信小程序组件
  17. 计算机网络专业调研报告前言,计算机网络专业调研报告材料.docx
  18. 恶意网站可利用浏览器扩展 API,窃取浏览器数据
  19. Mysql大表数据清理
  20. 应用于Web的TWAIN扫描识别软件-Dynamic Web TWAIN

热门文章

  1. 22年全国程序员1月薪资出炉,年收入 40 万以上的人为何那么多?
  2. JVM:这次一定要搞懂字节码
  3. 高新技术企业的八大领域及要点
  4. 基于python的国内外研究现状怎么写_如何写国内外研究现状
  5. 十三届双11,一部电商流量变迁史
  6. python毕业设计基于django框架的个人博客系统的设计与实现 毕设参考
  7. 基于遥感的大蒜种植面积量测
  8. 从蓝光到4K,腾讯视频高码率下载背后的技术
  9. 关于小数四舍五入的方式
  10. 2022-07-10 第八小组 张明敏 学习笔记