這題有點坑,主要是題意理解上,編碼都比較簡單。
先說明下題意,一個球館有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;
}