1026 Table Tennis (PAT Advanced) 坑点

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

送两个测试点:

3
20:50:00 30 0
20:51:00 5 0
20:57:00 20 0
2 1
2
5
08:05:00 15 0
08:10:00 10 0
08:11:00 5 1
08:12:00 10 0
08:20:00 15 1
2 1
2

 

C Code: 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <limits.h>

#define MAX_N 10010
#define MAX_K 110

int n, k, m;

typedef struct _PLAYER
{
    int arriving_time; // in second, count from 00:00:00
    int duration; // in second
    int is_vip;
    int visited;
    int serving_time;
} Player;

Player player_lst[MAX_N];
int queue_front = 0, queue_rear = 0;

typedef struct _TABLE
{
    int is_empty;
    int leaving_time; // in second, count from 00:00:00
    int player_id; // index in player_lst
    int serving_count;
} Table;

Table table_lst[MAX_K]; // table numbered from 1 to k
int vip_tables[MAX_K];

int vip_queue[MAX_N];
int vip_count;
int vip_front, vip_rear;
int have_not_arrived;

// compare functions

int comp_arriving_time(const void *_a, const void *_b)
{
    return ((Player*)_a)->arriving_time - ((Player*)_b)->arriving_time;
}

int comp(const void *_a, const void *_b)
{
    return *(int*)_a - *(int*)_b;
}

int comp_serving_time(const void *_a, const void *_b)
{
    Player *a = (Player*)_a, *b = (Player*)_b;
    if(a->visited != b->visited) return a->visited - b->visited;
    else return a->serving_time - b->serving_time;
}

// time convertions

int hms_to_s(int h, int m, int s)
{
    return h * 3600 + m * 60 + s;
}

void s_to_hms(int ts, char *buffer)
{
    int h, m, s;
    s = ts % 60;
    ts /= 60;
    m = ts % 60;
    h = ts / 60;

    buffer[0] = h / 10 + '0';
    buffer[1] = h % 10 + '0';

    buffer[2] = ':';

    buffer[3] = m / 10 + '0';
    buffer[4] = m % 10 + '0';

    buffer[5] = ':';

    buffer[6] = s / 10 + '0';
    buffer[7] = s % 10 + '0';

    buffer[8] = '\0';
}

// functional
int all_table_empty()
{
    for(int i = 1; i <= k; ++i)
        if(table_lst[i].is_empty == 0) return 0;
    return 1;
}

int any_table_empty()
{
    for(int i = 1; i <= k; ++i)
        if(table_lst[i].is_empty) return 1;
    return 0;
}

int any_vip_table_empty()
{
    for(int i = 0; i < m; ++i)
        if(table_lst[vip_tables[i]].is_empty) return 1;
    return 0;
}

int get_empty_vip_table()
{
    int i, tmp_table_id;
    for(i = 0; i < m; ++i)
        if(table_lst[vip_tables[i]].is_empty) break;
    tmp_table_id = vip_tables[i];
    return tmp_table_id;
}

void squeeze_queue()
{
    while(queue_front < queue_rear && player_lst[queue_front].visited)
        queue_front++;
}

int take_first_vip()
{
    vip_count--;
    int tmp_player_id = vip_queue[vip_front++];
    return tmp_player_id;
}

int is_queue_empty()
{
    return queue_front == queue_rear;
}

int get_empty_table()
{
    int i, tmp_table_id;
    for(i = 1; i <= k; ++i)
        if(table_lst[i].is_empty) break;
    tmp_table_id = i;
    return tmp_table_id;
}

int take_queue_front()
{
    int tmp_player_id = queue_front++;
    if(player_lst[tmp_player_id].is_vip) // 难点:队头可能是一个vip而又没有vip桌
    {
        vip_count--;
        vip_front++;
    }
    return tmp_player_id;
}

int take_next_to_come()
{
    --have_not_arrived;
    queue_rear++;
    return queue_front++;
}

void take_table(int player_id, int table_id)
{
    player_lst[player_id].visited = 1;
    table_lst[table_id].is_empty = 0;
    table_lst[table_id].serving_count++;
    table_lst[table_id].player_id = player_id;
    table_lst[table_id].leaving_time = player_lst[player_id].serving_time + player_lst[player_id].duration;
    squeeze_queue(); // 比起这个做法,还是使用一个数记录下等待队列的长度比较靠谱(对于中间挖了洞的情况)
}

int get_next_person_arriving_time()
{
    if(queue_rear < n)
        return player_lst[queue_rear].arriving_time;
    else
        return hms_to_s(23, 59, 59);
}

void enqueue_next_person()
{
    if(player_lst[queue_rear].is_vip)
    {
        ++vip_count;
        vip_queue[vip_rear++] = queue_rear;
    }
    //printf("player %d enqueued\n", queue_rear);
    queue_rear++;
    have_not_arrived--;
}

void service_complete(int table_id)
{
    //printf("player %d leave table %d\n", table_lst[table_id].player_id, table_id);
    table_lst[table_id].is_empty = 1;
}

void get_min_leaving_time(int *next_leaving_time, int *next_leave_table)
{
    *next_leaving_time = INT_MAX;
    *next_leave_table = 0;
    for(int i = 1; i <= k; ++i)
        if(!table_lst[i].is_empty && table_lst[i].leaving_time < *next_leaving_time)
        {
            *next_leaving_time = table_lst[i].leaving_time;
            *next_leave_table = i;
        }
}

int main()
{
    int tmp_h, tmp_m, tmp_s;
    scanf("%d", &n);
    have_not_arrived = n;
    for(int i = 0; i < n; ++i)
    {
        scanf("%d:%d:%d %d %d", &tmp_h, &tmp_m, &tmp_s, &player_lst[i].duration, &player_lst[i].is_vip);
        if(player_lst[i].duration > 120) player_lst[i].duration = 120; // 坑:题干Assume时间不超过120但是测试点4卡这个
        player_lst[i].duration *= 60;
        player_lst[i].arriving_time = hms_to_s(tmp_h, tmp_m, tmp_s);
    }

    qsort(player_lst, n, sizeof(Player), comp_arriving_time);

    scanf("%d%d", &k, &m);
    for(int i = 0; i < m; ++i)
    {
        scanf("%d", &vip_tables[i]);
    }

    for(int i = 1; i <= k; ++i)
    {
        table_lst[i].is_empty = 1;
    }

    qsort(vip_tables, m, sizeof(int), comp);

    const int closing_time = hms_to_s(21, 0, 0);
    int next_leaveing = closing_time, next_leave_table = 0; // if we have a priority-queue to maintain next_leaveing
    int prev_leaving = hms_to_s(8, 0, 0);
    int next_arriving = get_next_person_arriving_time();
    int tmp_table_id, tmp_player_id;

    while( !(all_table_empty() && !have_not_arrived && (is_queue_empty() || prev_leaving >= closing_time)) ) // 难点:退出条件
    {
        while(any_table_empty() && prev_leaving < closing_time)
        {
            // get into service
            if(!is_queue_empty()) // mind the visited person
            {
                if(vip_count > 0 && any_vip_table_empty())
                {
                    tmp_table_id = get_empty_vip_table(); // get and remove the vip table
                    tmp_player_id = take_first_vip(); // get the first vip and dequeue
                }
                else
                {
                    tmp_table_id = get_empty_table();
                    tmp_player_id = take_queue_front(); // mind the visited person
                }
                
                player_lst[tmp_player_id].serving_time = prev_leaving;
            }
            else if(have_not_arrived > 0 && next_arriving < next_leaveing) // 边界条件:有人走的同时有人来,人先走,再分配球台
            {
                tmp_player_id = take_next_to_come(); // move both queue_front and queue_rear to the next, edit have_not_arrived
                // 坑:如果有是vip且有vip桌空着,他们会优先选择VIP桌(题目里没说)
                if(player_lst[tmp_player_id].is_vip && any_vip_table_empty())
                    tmp_table_id = get_empty_vip_table();
                else
                    tmp_table_id = get_empty_table();
                
                player_lst[tmp_player_id].serving_time = player_lst[tmp_player_id].arriving_time;
                next_arriving = get_next_person_arriving_time();
            }
            else
            {
                break;
            }

            //printf("player %d on table %d\n", tmp_player_id, tmp_table_id);
            take_table(tmp_player_id, tmp_table_id); // update table info and mark the player visited
            if(table_lst[tmp_table_id].leaving_time < next_leaveing)
            {
                next_leaveing = table_lst[tmp_table_id].leaving_time;
                next_leave_table = tmp_table_id;
            }
        }
        while(have_not_arrived && next_arriving <= next_leaveing) // 边界条件:就算下一次有人离开的同时有人来了,此人也要去排队
        {
            // get into queue
            enqueue_next_person(); // mind vip
            next_arriving = get_next_person_arriving_time();
        }
        while(!all_table_empty())
        {
            // 边界条件:有人同时离开时,要先处理所有离开,再让人排队。这时如果恰好有人一起进来,先让他们排队,再处理队列
            prev_leaving = next_leaveing;
            service_complete(next_leave_table);
            get_min_leaving_time(&next_leaveing, &next_leave_table);
            if(prev_leaving != next_leaveing)
                break;
        }
    }

    // visited will be 0 for the not served person
    // then just sort
    qsort(player_lst, n, sizeof(Player), comp_serving_time);
    char buffer[10];
    int i = 0;
    while(i < n && !player_lst[i].visited) ++i;
    for(; i < n; ++i)
    {
        s_to_hms(player_lst[i].arriving_time, buffer);
        printf("%s ", buffer);
        s_to_hms(player_lst[i].serving_time, buffer);
        printf("%s ", buffer);
        printf("%d\n", (int)round((player_lst[i]. serving_time - player_lst[i].arriving_time) / 60.0f));
    }
    for(i = 1; i < k; ++i)
    {
        printf("%d ", table_lst[i].serving_count);
    }
    printf("%d", table_lst[k].serving_count);

    return 0;
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值