1026 Table Tennis (30分)

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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
The following is the data that you can add to your input file (as an example). Notice that the first line is going to be a line representing your own hobbies. In my case, it is the Vitaly,table tennis,chess,hacking line. Your goal is to create a class called Student. Every Student will contain a name (String) and an ArrayList<String> storing hobbies. Then, you will add all those students from the file into an ArrayList<Student>, with each Student having a separate name and ArrayList of hobbies. Here is an example file containing students (the first line will always represent yourself). NOTE: eventually, we will have a different file containing all our real names and hobbies so that we could find out with how many people each of us share the same hobby. Vitaly,table tennis,chess,hacking Sean,cooking,guitar,rainbow six Nolan,gym,piano,reading,video games Jack,cooking,swimming,music Ray,piano,video games,volleyball Emily,crochet,drawing,gardening,tuba,violin Hudson,anime,video games,trumpet Matt,piano,Reading,video games,traveling Alex,swimming,video games,saxophone Roman,piano,dancing,art Teddy,chess,lifting,swimming Sarah,baking,reading,singing,theatre Maya,violin,knitting,reading,billiards Amy,art,gaming,guitar,table tennis Daniel,video games,tennis,soccer,biking,trumpet Derek,cooking,flute,gaming,swimming,table tennis Daisey,video games,guitar,cleaning,drawing,animated shows,reading,shopping Lily,flute,ocarina,video games,baking Stella,roller skating,sudoku,watching baseball,harp Sophie,viola,ukulele,piano,video games
06-10

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁星蓝雨

如果觉得文章不错可以请喝咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值