题目来源
注意点:
- 牛客的数据会弱一点,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
思路简介
这题不涉及算法,单纯的模拟,但是坑特别多,如果你过不了可能是下面的问题:
- 对于 vip 的分配
- 如果 vip 进入队列时,有空的桌子,那么要尝试寻找 vip 桌,vip 会被分配到编号最小的 vip 桌,而不是编号最小的空桌子
- 可能会有多张桌子在同一时刻空闲,这时,等待队列当中的分配顺序是先尝试给 vip 分配vip桌子,再考虑普通人
- 如果没有 vip 桌子可以分配,那么 vip 会被视作普通人,轮到才分配
- round是四舍五入取整,不是向上取整(牛客没有这个样例,PTA第8个测试点是)
- 可能会出现 21 点来到的用户,此时不应把这种用户加入计算
- 可能会出现游玩时间大于 2 小时的用户,此时应当将他们的游玩时间取 2 小时(牛客上的最后一个样例,PTA的第 6 还是第 7 忘记了 )
- 输出按照服务时间排序,但是不要用 sort ,因为如果普通人和 vip 同时分配,如果有 vip桌子,vip 应当排在普通人之前
- PTA 上有格式要求,末尾不能有空格,同时要多输出一个换行
最后我的实现是采用 vip 和 ordinary 双队列,用 vector 维护
我没有设置等待时间,而是设置了每个桌子的空闲时间
这样如果有空闲的桌子就直接分配
没有空闲的桌子就要进入 vip 调度
遇到的问题
- round 想破头皮都没想到是四舍五入,一直错
- 没考虑空桌子分给 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 桌子
- 没考虑同时有多个桌子空闲时,先分 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;
}