解题总结
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;
}