【PAT甲级真题】- Table Tennis (30)

题目来源

Table Tennis (30) - PTA

Table Tennis (30) - 牛客

注意点:

  • 牛客的数据会弱一点,PTA 会强一点
  • 太多注意点了,思路吧
    这题从昨晚写到今晚,给个关注吧(哭),真的很难写。。。

题目描述

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.

输入描述:

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.

输出描述:

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.

##输入例子:

复制代码
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

输出例子:

复制代码
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 的分配
    • 如果 vip 进入队列时,有空的桌子,那么要尝试寻找 vip 桌,vip 会被分配到编号最小的 vip 桌,而不是编号最小的空桌子
    • 可能会有多张桌子在同一时刻空闲,这时,等待队列当中的分配顺序是先尝试给 vip 分配vip桌子,再考虑普通人
    • 如果没有 vip 桌子可以分配,那么 vip 会被视作普通人,轮到才分配
  2. round是四舍五入取整,不是向上取整(牛客没有这个样例,PTA第8个测试点是)
  3. 可能会出现 21 点来到的用户,此时不应把这种用户加入计算
  4. 可能会出现游玩时间大于 2 小时的用户,此时应当将他们的游玩时间取 2 小时(牛客上的最后一个样例,PTA的第 6 还是第 7 忘记了 )
  5. 输出按照服务时间排序,但是不要用 sort ,因为如果普通人和 vip 同时分配,如果有 vip桌子,vip 应当排在普通人之前
  6. PTA 上有格式要求,末尾不能有空格,同时要多输出一个换行

最后我的实现是采用 vip 和 ordinary 双队列,用 vector 维护

我没有设置等待时间,而是设置了每个桌子的空闲时间

这样如果有空闲的桌子就直接分配

没有空闲的桌子就要进入 vip 调度

遇到的问题

  1. round 想破头皮都没想到是四舍五入,一直错
  2. 没考虑空桌子分给 vip 的情况,因为题目中说 "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.",我以为是 vip 在有空桌子的时候会直接分最小的,其实是先分 vip 桌子
  3. 没考虑同时有多个桌子空闲时,先分 vip

代码

cpp 复制代码
/**
 * https://www.nowcoder.com/pat/5/problem/4013
 * 模拟
 */
#include<bits/stdc++.h>
using namespace std;

int time_to_sec(string str){
    istringstream ss(str);
    int h,m,s;
    char c;
    ss>>h>>c>>m>>c>>s;
    return h*3600+m*60+s;
}

string sec_to_time(int sec){
    int h=sec/3600;
    int m=(sec%3600)/60;
    int s=sec%60;
    char buffer[10];
    sprintf(buffer,"%02d:%02d:%02d",h,m,s);
    return string(buffer);
}

struct People{
    int arr_time,play_time;
    int serve_time;
    People():arr_time(0),play_time(0),serve_time(-1){}
    People(int a,int p):arr_time(a),play_time(p),serve_time(-1){}
};

struct Table{
    int free_time,serve_num;
    int is_vip_table;

    Table():free_time(time_to_sec("08:00:00")),serve_num(0),is_vip_table(0){}
};

bool cmp(People a,People b){
    return a.arr_time<b.arr_time;
}

int peo_num,table_num,vip_table_num;
vector<People>ordinarys,vips,res;
Table table[107];
int end_time=time_to_sec("21:00:00");

void input(){
    cin>>peo_num;
    for(int i=0;i<peo_num;++i){
        string arr_time;
        int play_time,is_vip;
        cin>>arr_time>>play_time>>is_vip;
        play_time*=60;
        play_time = min(play_time, 7200);  // 必须添加
        if(time_to_sec(arr_time)>=end_time)continue;
        if(!is_vip)ordinarys.emplace_back(time_to_sec(arr_time),play_time);
        else vips.emplace_back(time_to_sec(arr_time),play_time);
    }

    cin>>table_num>>vip_table_num;
    for(int i=0;i<vip_table_num;++i){
        int t;cin>>t;
        table[t-1].is_vip_table=1;
    }

    sort(ordinarys.begin(),ordinarys.end(),cmp);
    sort(vips.begin(),vips.end(),cmp);
}

vector<int> find_table(People p){
    int mi=25*3600;

    //res1空闲的桌子,res2等待最小时间的桌子
    vector<int>res1,res2;
   
    for(int i=0;i<table_num;++i){
        if(table[i].free_time<=p.arr_time)
            res1.emplace_back(i);
        

        if(table[i].free_time<mi){
            mi=table[i].free_time;
            res2.clear();
            res2.emplace_back(i);
        }else if(table[i].free_time==mi)
            res2.emplace_back(i);
        
    }
    if(res1.size())return res1;//有空桌就返回空桌
    return res2;//没有空桌返回最快的桌子
}

int find_vip_table(vector<int>t){
    for(auto x:t){
        if(table[x].is_vip_table)
            return x;
    }
    return -1;
}

void assign(People p,int is_vip,int vt,vector<int>num){
    if(p.arr_time>=end_time)return;//9点之后来的

    if(table[num[0]].free_time<=p.arr_time){//有空桌
        if(is_vip&&vt!=-1){//是vip
            table[vt].serve_num++;
            table[vt].free_time=p.arr_time+p.play_time;
            p.serve_time=p.arr_time;
        }else {//不是vip=是vip但是没有vip桌子
            table[num[0]].serve_num++;
            table[num[0]].free_time=p.arr_time+p.play_time;
            p.serve_time=p.arr_time;
        }
    }else {//没有空桌子
        if(table[num[0]].free_time>=end_time)return;//最快的桌子大于9点,关店
        if(is_vip&&vt!=-1){//是vip
            table[vt].serve_num++;
            p.serve_time=table[vt].free_time;
            table[vt].free_time+=p.play_time;
        }else {//不是vip=是vip但是没有vip桌子
            table[num[0]].serve_num++;
            p.serve_time=table[num[0]].free_time;
            table[num[0]].free_time+=p.play_time;
        }
    }

    res.emplace_back(p);
}

void solve(){
    int lenv=vips.size(),leno=ordinarys.size();
    int kv=0,ko=0;

    while(kv<lenv&&ko<leno){
        int vip_arr_time=vips[kv].arr_time;
        int ord_arr_time=ordinarys[ko].arr_time;
        
        if(vip_arr_time<=ord_arr_time){//vip先到,直接给分桌
            vector<int>num=find_table(vips[kv]);
            int vt=find_vip_table(num);
            assign(vips[kv++],1,vt,num);
        }else {//普通先到,如果等待要先分给vip
            vector<int>num=find_table(ordinarys[ko]);
            if(table[num[0]].free_time<=ord_arr_time){//有空桌子,直接分
                assign(ordinarys[ko++],0,-1,num);
            }else {//没有空桌子
                int vt=find_vip_table(num);
                if(table[num[0]].free_time>=vip_arr_time&&vt!=-1){//vip在等待时来到
                    assign(vips[kv++],1,vt,num);
                }else {
                    assign(ordinarys[ko++],0,-1,num);
                }
            }
        }
    }

    while(kv<lenv){
        vector<int>num=find_table(vips[kv]);
        int vt=find_vip_table(num);
        assign(vips[kv++],1,vt,num);
    }

    while(ko<leno){
        vector<int>num=find_table(ordinarys[ko]);
        assign(ordinarys[ko++],0,-1,num);
    }

    for(auto p:res){
        if(p.serve_time==-1||p.serve_time>=end_time)continue;
        cout<<sec_to_time(p.arr_time)<<' '<<sec_to_time(p.serve_time);
        cout<<' '<<round((double)(p.serve_time-p.arr_time)/60)<<'\n';
    }

    for(int i=0;i<table_num;++i){
        cout<<table[i].serve_num;
        if(i!=table_num-1)cout<<' ';
    }
    cout<<'\n';
}

int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //fstream in("in.txt",ios::in);cin.rdbuf(in.rdbuf());
    int T=1;
    //cin>>T;
    while(T--){
        input();
        solve();
    }
    return 0;
}
相关推荐
郝学胜_神的一滴10 小时前
CMake 30:循环语法全解|foreach_while双循环精讲、迭代技巧与实战避坑指南
c++·cmake
卷无止境2 天前
C++ 的Eigen 库全解析
c++
卷无止境2 天前
现代 C++特性大盘点:一门脱胎换骨的老语言
c++·后端
郝学胜_神的一滴2 天前
CMake 27:缓存变量的特性、语法、类型与实操全解
c++·cmake
博客18004 天前
酷宝的使用方法,超好用的免费界面库,C++、MFC可用
c++·mfc·界面库·库来帮·酷宝
郝学胜_神的一滴4 天前
CMake 026:属性体系精讲、四大作用域全解 & 实战代码落地
c++·cmake
众少成多积小致巨5 天前
JNI (Java Native Interface) 技术手册中文参考指南
android·java·c++
clint4569 天前
C++进阶(1)——前景提要
c++
夜悊9 天前
C++代码示例:进制数简单生成工具
c++
郝学胜_神的一滴9 天前
CMake 021: IF 条件判据详诠
c++·cmake