这题有点坑,主要是题意理解上,编码都比较简单。
先说明下题意,一个球馆有n个桌子从1到N编号,其中有k台vip桌子。随之,用户也有普通和vip之分。每次用户来时给其分配编号最小且可用的桌子,如果没有则等待。
附加条件:
1、每个人玩的时间不能超过2小时,超过则压缩成2小时(ps:PAT上好像有个银行排队的题,也是说服务时间不超过多少,不压缩能过,但是本题必须要压缩,不然会有个用例过不了)
2、球馆开门时间 8:00-21:00,且保证用户在此时间来到球馆,显然21:00到的要舍去,21:00前无法得到服务的也要舍去
4、vip桌可用时,如果有vip在等待,则第一个等待的vip可直接占用,无视普通用户。
比如 普通用户1 【8:00】到的,此时桌子满了,则其等待,vip1【9:00】到的,假设刚好一台vip桌在9:00可用,则这台桌子会分配给VIP而非普通用户。
3、最坑的一点,题目没有明说,我还是看了别人博客才知道的:虽然说的是每个人到来时分配最小编号的可用桌,但是对于VIP用户,如果有多台桌子可用(其中有vip桌),则优先分配编号最小的vip桌,而非编号最小的桌子。若只有普通桌,分配编号最小的普通桌子给他。
比如:vip1来时,普通1号桌,vip3号桌,vip4号桌都可使用,则分配vip3号桌给他。
4、输出的等待时间记得四舍五入!(30进1)
5、输出按得到服务的时间升序输出
解题思路:
显然要构造一个结构体去存储玩家信息:到达时间,玩的时间,是否是vip。还要按到来时间排序。
我还构造了一个结构体去记录结果。
我这里构造了两个queue,normalq(普通玩家),vipq(vip玩家),方便将其区分。
对于每张桌子设置一个判断是否是vip桌子的数组,一个记录服务人数的数组,
还要有一个记录endtime(可用时间)的数组,endtime初始值为8*3600。
每次取出,endtime最小的桌子,若endtime>=21*3600跳出循环。
然后根据其是否是vip桌,来从normalq和vipq中取出相应玩家去占有该桌,最后进行更新。
具体如何判断,我在下面的代码都写了相应的注释。
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <stdio.h>
#define maxn 101
using namespace std;
struct player{
int arrive,playtime,flag;//到来时间,玩游戏时间,是否是vip
player(string str,int playtime,int flag){
int h,m,s;
sscanf(str.c_str(),"%d:%d:%d",&h,&m,&s);
arrive=3600*h+60*m+s;
if(playtime>60*2) playtime=60*2;//进行压缩
this->playtime=playtime;
this->flag=flag;
}
player(){}
};
struct record{
int arrive,start,wait;//记录结果:到达时间,开始游戏时间,等待时间
record(int a,int s,int w){
arrive=a;
start=s;
wait=w;
}
};
int table[maxn];//记录endtime
int server[maxn]={0};//记录服务人数
bool viptable[maxn]={false};//记录是否是vip桌
queue<player> normalq,vipq;//普通玩家/vip玩家
vector<player> v;//接收输入,用于排序
vector<record> result;//记录结果
int n,k,m;
bool cmp(player p1,player p2){
return p1.arrive < p2.arrive;
}
bool cmp2(record r1,record r2){
return r1.start<r2.start;
}
int getTable(){//找到可用时间最小的桌子,若最小可用时间为21*3600 返回-1
int MIN=21*3600;
int index=-1;
for(int i=1;i<=k;i++){
if(table[i]<MIN){
index=i;
MIN=table[i];
}
}
return index;
}
int main()
{
cin>>n;
string str;
int playtime,flag;
for(int i=0;i<n;i++){
cin>>str>>playtime>>flag;
v.push_back(player(str,playtime,flag));
}
cin>>k>>m;
for(int i=0;i<m;i++){
int h;
cin>>h;
viptable[h]=true;
}
sort(v.begin(),v.end(),cmp);
for(int i=0;i<v.size();i++){//数据入队
if(v[i].flag==0){
normalq.push(v[i]);
}else{
vipq.push(v[i]);
}
}
for(int i=1;i<=k;i++){
table[i]=8*3600;
}
bool open=true;
while(open){
int index = getTable();
if(index==-1) break;
int endtime = table[index];
player p;
if(vipq.empty()&&normalq.empty()){
break;
}else if(vipq.empty()){
p=normalq.front();
normalq.pop();
}else if(normalq.empty()){
p=vipq.front();
vipq.pop();
}else{
//如果vip先到,无论这张桌子是否是vip桌,都会是vip先用
if(vipq.front().arrive<normalq.front().arrive||
//若是vip桌,且有vip在等待,无视普通用户,直接分给vip
(endtime>=vipq.front().arrive&&viptable[index]==true)){
p=vipq.front();
vipq.pop();
}else {
p=normalq.front();
normalq.pop();
}
}
if(p.arrive>=21*3600) break;
if(p.flag==1&&viptable[index]==false){
//比较重要的一点,也就是我说的第3个附加条件。如果当前用户是vip且分配给他的是普通桌
for(int i=1;i<=k;i++){//那么尝试去寻找是否有空闲的vip桌,并将其分给vip
if(viptable[i]==true&&table[i]==endtime){
index=i;
}
}
}
int starttime,wait;
if(p.arrive>=endtime){
starttime=p.arrive;
wait=0;
}else{
starttime=endtime;
wait=starttime-p.arrive;
}
server[index]++;
table[index]=starttime+p.playtime*60;
result.push_back(record(p.arrive,starttime,wait));
}
sort(result.begin(),result.end(),cmp2);
for(int i=0;i<result.size();i++){
int arrive=result[i].arrive,start=result[i].start,wait=result[i].wait;
printf("%02d:%02d:%02d %02d:%02d:%02d ",
arrive/3600,arrive%3600/60,arrive%3600%60,
start/3600,start%3600/60,start%3600%60);
if(wait%60>=30){
wait=wait/60+1;
}else{
wait=wait/60;
}
printf("%d\n",wait);
}
for(int i=1;i<=k;i++){
cout<<server[i];
if(i!=k) cout<<" ";
}
return 0;
}