1 题目
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
作者: CHEN, Yue
单位: 浙江大学
时间限制: 400 ms
内存限制: 64 MB
2 解析
2.1 题意
N个球员(把一对球员看成一个)到K张乒乓球桌训练,训练时长超2h(算作2h),K张球桌有M张VIP,如果有VIP球桌空闲,且等待队列中存在VIP球员,那么等待队列中VIP球员前往编号的最小VIP球桌训练;如果有VIP球桌空闲,但等待队列没有VIP球员,VIP球桌分配给等待队列中第一非VIP球员;如果没有VIP球桌空闲,VIP球员被看作普通球员处理。
2.2 思路
- 1创建结构体:对于球员:是否是VIP,到达时间,训练时间,开始训练时间;对于球桌:是否是VIP,服务人数,当前占用球桌的球员的结束训练时间;
- 2 把球员按到达时间从小到大排序;
- 3 分类讨论:
- 如果最早空闲的球桌idx是VIP球桌,且队首球员是VIP球员,那把球桌idx分配求它;
- 如果最早空闲的球桌idx是VIP球桌,且队首球员不是VIP球员,那把查看第一个VIP球员是否在球桌空闲之前到达:
- 如果是,那么就让VIP球员插队,把球桌idx分给该VIP球员;
- 否则,还是把球桌分配给队首球员。
- 如果最早空闲的球桌idx不是VIP球桌,且队首球员不是VIP球员,那么把球桌分配给他;
- 如果最早空闲的球桌idx不是VIP球桌,且队首球员是VIP球员,那把查看最早空闲的VIP球桌VIPidx是否在VIP球员到达之前空闲:
- 如果是,把球桌VIPidx分配给VIP球员;
- 否则, 把球桌idx分配给VIP球员。
- 等价时长应该严格的四舍五入,可以视同round或者在原数上加30取整。
- 对于不在21之前到达的球员不考虑。
- VIPi必须一开始就指向VIP球员。
- 21:00没有开始训练的,不在训练。
- 注意VIP球员插队情况以及VIP球员选择VIP球桌的情况。
3 参考代码
在#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
using std::sort;
using std::vector;
const int K = 110;
struct Player
{
int m_arrivingTime;
int m_startTime;
int m_trainTime;
bool m_isVip;
}newPlayer;
struct Table
{
int m_endTime;
int m_numServer;
bool m_isVip;
}table[K];
vector<Player> player;
int calTime(int h, int m, int s){
return h * 3600 + m * 60 + s;
}
bool cmpArriveTime(Player a, Player b){
return a.m_arrivingTime < b.m_arrivingTime;
}
bool cmpStartTime(Player a, Player b){
return a.m_startTime < b.m_startTime;
}
//从当前VIPi移到下一个VIP球员
int nextVIPPlayer(int VIPi){
VIPi++;
while(VIPi < player.size() && player[VIPi].m_isVip == false){
VIPi++;
}
return VIPi;
}
//把编号为tID的球桌分配给编号为pID的球员
void allocTable(int tID, int pID){
if(table[tID].m_endTime >= player[pID].m_arrivingTime){
player[pID].m_startTime = table[tID].m_endTime;
}else{
player[pID].m_startTime = player[pID].m_arrivingTime;
}
table[tID].m_endTime = player[pID].m_startTime + player[pID].m_trainTime;
table[tID].m_numServer++;
}
int main(int argc, char const *argv[])
{
int N, k, m, VipTable;
int edTime = calTime(21, 0, 0);
int stTime = calTime(8, 0, 0);
scanf("%d", &N);
for (int i = 0; i < N; ++i)
{
int h, m, s, trainTime, isVip;
scanf("%d:%d:%d %d %d", &h, &m, &s, &trainTime, &isVip);
int time = calTime(h, m, s);
if(time >= edTime) continue;
newPlayer.m_arrivingTime = time;
newPlayer.m_startTime = edTime;
newPlayer.m_trainTime = trainTime <= 120 ? trainTime * 60 : 7200;
newPlayer.m_isVip = isVip;
player.push_back(newPlayer);
}
scanf("%d%d", &k, &m);
for (int i = 1; i <= k; ++i)
{
table[i].m_isVip = table[i].m_numServer = 0;
table[i].m_endTime = stTime;
}
for (int i = 1; i <= m; ++i)
{
scanf("%d", &VipTable);
table[VipTable].m_isVip = true;
}
sort(player.begin(), player.end(), cmpArriveTime);
int i = 0, VIPi = -1;//扫描所有球员,扫描VIP球员
VIPi = nextVIPPlayer(VIPi);
while(i < player.size()){
int idx = -1, minEndTime = 1<<30;
for (int j = 1; j <= k; ++j)//寻找最早能空闲的桌子
{
if(table[j].m_endTime < minEndTime){
minEndTime = table[j].m_endTime;
idx = j;
}
}
if(table[idx].m_endTime >= edTime) break;//已关门,直接break
if(player[i].m_isVip == true && i < VIPi){
i++;//如果i号球员是vip,且VIPi > i,说明i号球员已经在训练
continue;
}
if(table[idx].m_isVip == true){//是VIP球桌
if(player[i].m_isVip == true){//1: VIP球桌 VIP球员
allocTable(idx, i);//桌子idx分配给球员i
if(VIPi == i){//找下一个VIP球员
VIPi = nextVIPPlayer(VIPi);
}
i++;//i号球员开始训练,寻找下一个球员
}else{ //2:VIP球桌,非VIP球员
//当前队首VIP球员比VIP球桌早(插队)
if(VIPi < player.size() && player[VIPi].m_arrivingTime <= table[idx].m_endTime){
allocTable(idx, VIPi);
VIPi = nextVIPPlayer(VIPi);
}else{//队首VIP球员比VIP桌晚,仍然把VIP桌分给球员i
allocTable(idx, i);
i++;
}
}
}else{
if(player[i].m_isVip == false){//3:非VIP球桌,非VIP球员
allocTable(idx, i);
i++;
}else{// 4:非VIP球桌,VIP球员
int VIPidx = -1, minVIPEndTime = 1<<30;
for (int j = 1; j <= k; ++j)
{
if(table[j].m_isVip == true && table[j].m_endTime < minVIPEndTime){
minVIPEndTime = table[j].m_endTime;
VIPidx = j;
}
}
//VIP球桌空闲的时间比球员来的早
if(VIPidx != -1 && player[i].m_arrivingTime >= table[VIPidx].m_endTime){
allocTable(VIPidx, i);
if(i == VIPi) VIPi = nextVIPPlayer(VIPi);
i++;
}else{//VIP球员来时,非VIP球桌还未空闲
allocTable(idx, i);
if(i == VIPi) VIPi = nextVIPPlayer(VIPi);
i++;
}
}
}
}
sort(player.begin(), player.end(), cmpStartTime);
for (int i = 0; i < player.size() && player[i].m_startTime < edTime; ++i)
{
int t1 = player[i].m_arrivingTime;
int t2 = player[i].m_startTime;
printf("%02d:%02d:%02d ", t1 / 3600, t1 % 3600 / 60, t1 % 60);
printf("%02d:%02d:%02d ", t2 / 3600, t2 % 3600 / 60, t2 % 60);
printf("%.0f\n", round((t2 - t1)/ 60.0));
}
for (int i = 1; i <= k ; ++i)
{
printf("%d", table[i].m_numServer);
if(i < k) printf(" ");
}
return 0;
}