PAT (Advanced Level) Practice 1026 Table Tennis (30分)

这题有点坑,主要是题意理解上,编码都比较简单。
先说明下题意,一个球馆有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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值