[PAT][ C++] 1026. Table Tennis (30)

本文介绍了一个乒乓球俱乐部的调度算法,该算法关注如何合理分配球桌资源给顾客,并考虑到VIP会员的优先级。通过分析顾客到达时间和游戏时长,算法能够计算出每位顾客的等待时间及每张球桌的服务人数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

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
解析

这道题目重点需要注意球桌与球员的分配规则。将队员按照到达时间排列,则规则可以总结如下:
1. 排列在队前的球员是VIP球员,
1) 寻找在他到达前已结束serve的编号最小的VIP球桌
2)如果到达之前没有结束serve的VIP球桌,则寻找编号最小的空闲的普通球桌
3)如果球员到达时无空闲球桌,则寻找结束时间最早的球桌,如果有多个球桌同时结束,则优先分配VIP球桌,如果无VIP球桌则优先分配编号最小的球桌
2. 排列在最前面的是普通球员
1)寻找球员到达时空闲球桌中编号最小的球桌分配给他
2)如果球员到达时无空闲球桌,则分配结束时间最早的编号最小的球桌分配给他
总结如下:
1、有球桌空闲,则优先分配编号最小的,如果是VIP球员,则优先分配空闲中的编号最小的VIP球桌
2、无球桌空闲,则需要等待,分配结束时间最早的球桌中编号最小的,如果是VIP球员,则选择符合条件中编号最小的
需要格外注意的是VIP球员优先分配VIP球桌。

代码
#include <bits/stdc++.h>
#include <iostream>

using namespace std;

struct Club
{
    int endTime,count;
    bool isVip;
    Club(int end=0,int c=0,bool vip=false):endTime(end),count(c),isVip(vip) {}
};

struct Person
{
    int arrive,start,cost;
    bool isVip;
    Person(int arr,int s,int c,bool vip):arrive(arr),start(s),cost(c),isVip(vip) {}
};

bool cmp(Person &p1,Person &p2){
    return p1.arrive<p2.arrive;

}

bool cmp2(Person &p1,Person &p2){
    return p1.start<p2.start;
}

void input(vector<Club> &club,vector<Person> &person){
    int n;
    scanf("%d",&n);
    int eight=8*3600,nine=21*3600;
    for(int i=0;i<n;i++){
        int h,m,s,p,f;
        scanf("%d:%d:%d %d %d",&h,&m,&s,&p,&f);
        int arr=h*3600+m*60+s;
        p=min(p,120)*60;
        if(arr>=nine) continue;
        //所有来打球的人初始化开始时间为晚上21点以后
        if(f==1){
            person.emplace_back(arr,nine+10,p,true);
        }
        else{
            person.emplace_back(arr,nine+10,p,false);
        }
    }
    int m,k;
    scanf("%d%d",&m,&k);
    for(int i=0;i<=m;i++){
        club.emplace_back(eight,0,false);
    }
    for(int i=0;i<k;i++){
        int num;
        scanf("%d",&num);
        club[num].isVip=true;
    }
}

void show(Person &p){
    if(p.start>=21*3600) return;
    int arrh=p.arrive/3600,arrm=p.arrive%3600/60,arrs=p.arrive%60;
    int sh=p.start/3600,sm=p.start%3600/60,ss=p.start%60;
    double err=(p.start-p.arrive)/60.0;
    printf("%02d:%02d:%02d %02d:%02d:%02d %.0f\n",arrh,arrm,arrs,sh,sm,ss,round(err));
}

//分配打球的player到特定的球台
void allocate(int index,int per,vector<Club> &club,vector<Person> &person){
    if(person[per].arrive<=club[index].endTime){
        person[per].start=club[index].endTime;
    }
    else{
        person[per].start=person[per].arrive;
    }
    club[index].endTime=person[per].start+person[per].cost;
    club[index].count++;
}

int main(){
    vector<Club> club;
    vector<Person> person;
    input(club,person);
    int len=person.size();
    int lenc=club.size();
    sort(person.begin(),person.end(),cmp);
    int per=0,nine=21*3600;
    for(int i=0;i<len&&per<len;i++){
        int earlyEnd=INT_MAX,index=-1;
        //如果没有球桌空闲则找到当前结束时间最早的球桌,如果有球桌空闲,则找到编号最小的空闲的球桌
        for(int j=1;j<lenc;j++){
            //在队列最前的球员到达之前,找到已空闲球桌中编号最小的
            if(club[j].endTime<=person[per].arrive){
                earlyEnd=club[j].endTime;
                index=j;
                break;
            }
            if(earlyEnd>club[j].endTime){
                earlyEnd=club[j].endTime;
                index=j;
            }
        }
        if(earlyEnd>=nine) break;
        if(club[index].isVip){      //如果当前空闲或结束时间最早的球桌是VIP球桌
            int k=per;
            //在当前等待人员中找到最靠前的VIP球员且还未开始打球
            while(k<len){
                if(person[k].isVip==true&&person[k].start>=nine)
                    break;
                k++;
            }
            //如果找到VIP球员且球员到达时间早于球桌结束时间则把球桌分配给他,如果没有找到则把球桌分配给队列最靠前球员
            if(k<len&&person[k].arrive<=earlyEnd){
                allocate(index,k,club,person);
            }
            else{
                allocate(index,per,club,person);
            }
        }
        else{                               //如果当前球桌不是VIP球桌
            //如果当前最靠前的球员是VIP球员,则寻找球员到达时的空闲球桌中找到编号最小的VIP球桌分配给他
            //如果球员到达时无空闲球桌,则分配结束时间最早的球桌给他
            if(person[per].isVip==true){    
                int vipearlyEnd=INT_MAX,vipindex=-1;
                for(int j=1;j<lenc;j++){
                    //寻找球员到达时已结束的球桌中编号最小的VIP球桌
                    if(club[j].isVip&&club[j].endTime<=person[per].arrive){
                        vipearlyEnd=club[j].endTime;
                        vipindex=j;
                        break;
                    }
                }
                //如果找到则分配VIP球桌,否则分配当前结束时间最早的球桌
                if(vipindex!=-1&&person[per].arrive>=vipearlyEnd){
                    allocate(vipindex,per,club,person);
                }
                else{
                    allocate(index,per,club,person);
                }
            }
            else{       //如果球桌不是VIP球桌,球员不是VIP球员,则分配当前球桌给当前球员
                allocate(index,per,club,person);
            }
        }
        //per指向队列中第一个还未开始的球员
        while(per<len&&person[per].start<=nine){
            per++;
        }
    }
    sort(person.begin(),person.end(),cmp2);
    for(int i=0;i<len&&person[i].start<nine;i++){
        show(person[i]);
    }
    for(int i=1;i<lenc;i++){
        if(i==1) printf("%d",club[i].count);
        else printf(" %d",club[i].count);
    }
    return 0;
}
如果您想读取.pat文件并添加内容,可以按照以下步骤操作: 1. 使用C++的fstream库打开.pat文件,例如: ```cpp #include <fstream> #include <iostream> int main() { std::ifstream file("example.pat"); if (file.is_open()) { // 文件成功打开,可以进行读取和写入操作 std::cout << "File opened successfully!\n"; } else { // 文件打开失败,输出错误信息 std::cerr << "Failed to open file!\n"; } return 0; } ``` 2. 读取文件内容并添加新内容,例如: ```cpp #include <fstream> #include <iostream> int main() { std::ifstream file("example.pat"); if (file.is_open()) { // 文件成功打开,可以进行读取和写入操作 std::cout << "File opened successfully!\n"; // 读取文件内容 std::string line; while (std::getline(file, line)) { std::cout << line << '\n'; } // 添加新内容 std::ofstream outfile("example.pat", std::ios::app); if (outfile.is_open()) { outfile << "New content\n"; std::cout << "New content added successfully!\n"; } else { std::cerr << "Failed to add new content!\n"; } } else { // 文件打开失败,输出错误信息 std::cerr << "Failed to open file!\n"; } return 0; } ``` 3. 关闭文件,例如: ```cpp #include <fstream> #include <iostream> int main() { std::ifstream file("example.pat"); if (file.is_open()) { // 文件成功打开,可以进行读取和写入操作 std::cout << "File opened successfully!\n"; // 读取文件内容 std::string line; while (std::getline(file, line)) { std::cout << line << '\n'; } // 添加新内容 std::ofstream outfile("example.pat", std::ios::app); if (outfile.is_open()) { outfile << "New content\n"; std::cout << "New content added successfully!\n"; } else { std::cerr << "Failed to add new content!\n"; } // 关闭文件 file.close(); outfile.close(); } else { // 文件打开失败,输出错误信息 std::cerr << "Failed to open file!\n"; } return 0; } ``` 这样您就可以读取.pat文件并添加新内容了。请注意,在添加新内容时,我们使用了std::ofstream库和std::ios::app参数来打开文件以追加内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值