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;
}

 

發佈了79 篇原創文章 · 獲贊 52 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章