解題總結
1.邏輯提前理清楚,條件都用文檔寫出來
2.代碼量大的時候善用代碼塊隱藏和功能註釋
3.若限制條件交叉,則選擇以某一個爲基礎,展開不同情況往下討論
寫題路程
卡住的點:
1.不能用我自己原來的寫法(優先隊列模擬最先空餘的桌子),因爲VIP桌子編號不定,不好處理,則直接遍歷所有桌子,分類討論
2.現在隊首的顧客來時,可能已經有很多個空閒的桌子,而要取滿足要求的編號最小的桌子而非最早空閒的桌子
條件:
1.若此時有VIP桌子空閒
(1)此時已經有VIP顧客到達,則放第一個到的VIP
(2)此時沒有已經到的VIP顧客,則放第一個到的顧客
2.此時VIP顧客在隊首
(1)有空閒的VIP桌
(2)沒有空閒的VIP桌
(i)有空閒的桌
(ii)沒有空閒的桌,選最早空閒的桌子
題解思路
結合兩個限制因素分類討論,第一層大循環是顧客(此事時間),然後第二層循環內得到最早空閒的桌子,分情況討論
1.第一個空閒的桌子是VIP桌子
(1)此時有到來的vip會員
(2)此時沒有到來的vip會員
直接選此時隊首的顧客
2.第一個空閒的桌子是普通桌子
(1)隊首是vip會員
(i)此時有空閒的vip桌子,選編號最小的
(ii)此時沒有空閒的vip桌子
(a)此時有空閒的普通桌,選編號最小的
(b)此時沒有空閒的桌,選最早空閒的
(2)隊首是普通顧客
(i)選編號最小的空閒桌子(此時是取普通桌)
你一定能保證這是普通桌子嗎???
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
struct player{
int arrive, serve, progress, wait, isVip;
int used;
};
struct table{
int isVip, cnt, vacant;
};
vector<table> tables;
vector<player> players;
bool cmpPlayer(player a, player b){
return a.arrive < b.arrive;
}
bool cmpStartServe(player a, player b){
return a.serve < b.serve;
}
int main(){
int N, K, M;
scanf("%d", &N);
for(int i = 0; i < N; i++){
player temp;
int h, s, m, vip, playingTime;
scanf("%d:%d:%d %d%d", &h, &m, &s, &playingTime, &vip);
temp.arrive = 3600*h + 60*m + s;
temp.progress = (playingTime < 120 ? 60*playingTime: 2*60*60);
temp.isVip = vip;
temp.used = 0;
if(temp.arrive < 21*3600) players.push_back(temp);
//來晚的人不管
}
sort(players.begin(), players.end(), cmpPlayer);
//輸入顧客且排序沒問題;
scanf("%d%d", &K, &M);
for(int i = 0; i < K; i++){
table temp;
temp.cnt = 0, temp.vacant = 8*3600;
temp.isVip = 0;//忘記初始化vip
tables.push_back(temp);
}
//tables下標數組從0開始,而桌子編號從1開始!
for(int i = 0; i < M; i++){
int x;
scanf("%d", &x);
tables[x-1].isVip = 1;
}
for(int i = 0; i < players.size(); ){
while(players[i].used) i++;//找到沒有招待過的顧客爲止
if(i >= players.size()) break;//全都招待過了,退出
int min_vacant = 21*60*60 + 1, min_index = -1;
//找出編號最小的最早空閒的桌子
//但這樣無法保證有vip桌的時候讓VIP先進去啊。
for(int j = 0; j < tables.size(); j++){
if(min_vacant > tables[j].vacant){
min_vacant = tables[j].vacant;
min_index = j;
}
}
if(min_vacant >= 21*60*60) break;//已經過了時間,退
//若是vip桌子,若有已經到達的vip顧客就放進去
if(tables[min_index].isVip){
int j;
for(j = 0; j < players.size(); j++){
//找到隊列中一個沒服務過的vip則退出
if(players[j].isVip && players[j].used == 0 && players[j].arrive <= tables[min_index].vacant)
break;
}
//找到了符合要求的vip,更新顧客和桌子信息
if(j < players.size()){
players[j].used = 1;
players[j].serve = max(players[j].arrive,min_vacant);
players[j].wait = (players[j].arrive<min_vacant?min_vacant-players[j].arrive:0);
tables[min_index].cnt++;
tables[min_index].vacant = players[j].serve + players[j].progress;
}
//否則直接取一個未遍歷過的第一個顧客即可
else{
players[i].used = 1;
players[i].serve = max(players[i].arrive,min_vacant);
players[i].wait = (players[i].arrive<min_vacant?min_vacant-players[i].arrive:0);
tables[min_index].cnt++;
tables[min_index].vacant = players[i].serve + players[i].progress;
i++;
}
}else{//找到的是普通桌子
//若第一個顧客是vip,則看是否有在他到來之前已經空閒的VIP桌子
if(players[i].isVip){
int qwq;
for(qwq = 0; qwq < tables.size(); qwq++)
if(tables[qwq].isVip && tables[qwq].vacant <= players[i].arrive){
min_index = qwq;
break;
}
//若找到空閒vip桌子,則將Min_index賦值爲其下標換
//沒找到空閒vip桌子,直接去空閒的編號最小的桌子.
if(qwq == tables.size()){
//尋找一來就空閒的編號最小的桌子,有則換其下標爲Min_index
int ri;
for(ri = 0; ri < tables.size(); ri++)
if(tables[ri].vacant <= players[i].arrive){
min_index = ri;
break;
}
}
}
//第一個顧客是普通顧客
else{
//找有沒有閒置的桌,有則取編號最小的爲min_index,沒有則還是默認的min——index
int ri;
for(ri = 0; ri < tables.size(); ri++)
if(tables[ri].vacant <= players[i].arrive){
min_index = ri;
break;
}
}
players[i].used = 1;
players[i].serve = max(players[i].arrive,tables[min_index].vacant);
players[i].wait = (players[i].arrive<tables[min_index].vacant?tables[min_index].vacant-players[i].arrive:0);
tables[min_index].cnt++;
tables[min_index].vacant = players[i].serve + players[i].progress;
i++;
}
}
sort(players.begin(), players.end(), cmpStartServe);
for(int i = 0; i < players.size(); i++){
if(players[i].used == 0) continue;
int h1 = players[i].arrive/3600, m1 = (players[i].arrive - 3600*h1)/60 , s1 = players[i].arrive%60;
int h2 = players[i].serve/3600, m2 = (players[i].serve - 3600*h2)/60 , s2 = players[i].serve%60;
int wait_min = (players[i].wait + 30)/60;//等待時間四捨五入!~
printf("%02d:%02d:%02d %02d:%02d:%02d %d\n", h1, m1, s1, h2, m2, s2, wait_min);
}
for(int i = 0; i < tables.size(); i++){
if(i) printf(" ");
printf("%d", tables[i].cnt);
}
return 0;
}