这篇文章帮我解决了测试点5、7
测试点分析都在代码注释里了
#include<bits/stdc++.h>
using namespace std;
int N, K, M; // 球友对的数量、球桌数、VIP球桌数
const int OpenTime = 28800; // 开门时间 8点
const int CloseTime = 75600; // 关门时间 21点
struct Player {
int arrvTime; // 球友到达时间
int playTime; // 球友占用球桌的时间
int waitTime; // 球友等待时间
bool isVipPly;// 球友是不是vip
int num; // 球友的输出的编号
Player(): arrvTime(OpenTime), playTime(0), waitTime(0),isVipPly(false), num(0xffffff) {
}
};
struct Table {
int EndTime; // 上一对球友打完球离开该球桌的时间
bool isVipTbl;// 是不是vip桌
int serveNum; // 桌子招待过多少球友
Table():EndTime(OpenTime), isVipTbl(false), serveNum(0) {
}
};
int main() {
Player player[10000];
Table table[101];
bool VipIsIn[10000] = {
false}; // 记录当前VIP是否已被处理过,防止当前处理到的是之前已经服务过的的VIP
cin >> N;
int realN = 0; // 记录符合要求的输入数据(到达时间在21点之前的球友)
for(int i = 0;i < N;++i) {
// 输入:每队球友的到达时间、占用球桌的时间(最多不能超过两小时)、是否是VIP
int h, m, s, playT, isVip;
scanf("%d:%d:%d %d %d\n", &h, &m, &s, &playT, &isVip);
int arvT = (h*60 + m)*60 + s; // 按照秒数记录player到达时间
if(arvT < CloseTime){
// 针对测试点3,到达时间刚好为21点,要舍去这个输入
player[realN].arrvTime = arvT;
player[realN].playTime = playT > 120 ? 120*60 : playT*60; // 针对测试点4,打球超过2小时的都要强制变成120分钟
player[realN].isVipPly = isVip;
realN++;
}
}
N = realN; // 将N变成真正有效的player个数
// 输入有关球桌的数据
cin >> K >> M;
for(int i = 0;i < M;++i) {
int tableID;
cin >> tableID;
table[tableID].isVipTbl = true; // 标记vip桌
}
sort(player, player+N, [](Player &a, Player &b){
// 按照到达时间排序
return a.arrvTime < b.arrvTime;
});
queue<int> VIPS; // 将VIP按照到达时间放入一个单独的队列
for(int i = 0;i < N;++i)
if(player[i].isVipPly)
VIPS.push(i);
/*** 算法开始(太难了呀!!) ***/
int numb = 0; // 记录球友开始打球的顺序
for(int i = 0;i < N;++i) {
// 如果当前选手i是已经被提前处理的VIP,那就不能处理要跳过
if(VipIsIn[i]) continue;
//找到最小结束时间的桌子
int minTableID = -1;
int minEndTime = 0xffffff;
for(int j = 1;j <= K;++j) {
if(table[j].EndTime < minEndTime){
minTableID = j;
minEndTime = table[j].EndTime;
}
}
Player &Pl = player[i]; // 当前要处理的player的引用
Player &vipPl = player[VIPS.front()]; // 当前队列中第一个vip的引用
// 如果最早结束的桌子的结束时间超过了21点,那当前和后面到达的选手都不能处理输出
if(table[minTableID].EndTime >= CloseTime) {
// 测试点0、8(测试点8是等于号)
Pl.num = 0xffffff; // 标记为无效,不能输出
break; // 因为每个选手的num一开始就都初始化为0xffffff,所以可以直接break;否则要continue
}
// 测试点5、7:vip用户要选择第一张空闲的vip桌
if(Pl.isVipPly && !table[minTableID].isVipTbl){
// 当前选手是VIP选手,要选择空闲的普通桌子和VIP桌子中选择VIP桌子
for(int j = 1; j <= K; j++){
if(Pl.arrvTime >= table[j].EndTime && table[j].isVipTbl){
//测试点7在这个等于号
minTableID = j;
break;
}
}
}
/******* 终于找到了正确的桌子 *******/
Table &Tb = table[minTableID];
// 如果vip和非vip都需要等待,而且空出来的球桌是VIP球桌,那就让VIP优先
if(vipPl.arrvTime < Tb.EndTime && Pl.arrvTime < Tb.EndTime &&
Tb.isVipTbl && !VIPS.empty()) {
// !VipIsIn[i]是防止当前处理到的是之前已经服务过的的VIP
// 处理的是队伍中当前选手i的后面的VIP选手
vipPl.waitTime = (Tb.EndTime - vipPl.arrvTime);
Tb.EndTime += vipPl.playTime;
VipIsIn[VIPS.front()] = true; // 记录该VIP已被服务过,防止后面遍历到他又处理一遍
vipPl.num = numb; // 记录输出顺序
i--; // 因为处理的是当前选手i后面的VIP选手,这一次的循环没有处理选手i,所以要i--抵消i++来停下处理当前选手i
VIPS.pop(); // 处理完当前VIP了
} else {
// 当前选手不是的VIP选手 或者 是VIP选手但当成普通选手的VIP选手(空闲球桌不是VIP球桌)
if(Pl.arrvTime < Tb.EndTime) {
// 需要等待
Pl.waitTime = (Tb.EndTime - Pl.arrvTime);
Tb.EndTime += Pl.playTime;
} else {
// 不需要等待
Tb.EndTime = Pl.arrvTime + Pl.playTime;
}
Pl.num = numb; // 记录输出顺序
/* VIP选手没碰上VIP发挥作用的情况(也就是当前处理的选手是VIP但是把他当普通选手处理了
所以要在VIP队列里删除他,并且标记该VIP为已经处理过) */
if(Pl.isVipPly){
// 这个超关键
VipIsIn[i] = true;
VIPS.pop();
}
}
numb++; // 因为有i--,所以用numb来标记输出顺序
Tb.serveNum++; // 统计桌子招待选手数量
}
sort(player, player+N, [](Player &a, Player &b){
// 按照记录的输出标记顺序来输出
return a.num < b.num;
});
for(int i = 0;i < N;++i) {
Player &Pl = player[i];
if(Pl.num == 0xffffff) continue; // 超过21点才能打球的球友就不能输出了
int ah = Pl.arrvTime/3600, am = Pl.arrvTime%3600/60, as = Pl.arrvTime%60;
int bh = (Pl.arrvTime+Pl.waitTime)/3600, bm = (Pl.arrvTime+Pl.waitTime)%3600/60, bs = (Pl.arrvTime+Pl.waitTime)%60;
// 等待的分钟数要四舍五入
if(player[i].waitTime%60 >= 30) {
player[i].waitTime = player[i].waitTime/60 + 1;
} else {
player[i].waitTime = player[i].waitTime/60;
}
printf("%02d:%02d:%02d %02d:%02d:%02d %d\n",ah,am,as,bh,bm,bs,player[i].waitTime);
}
for(int i = 1;i <= K;++i) {
cout << table[i].serveNum << (i == K?"\n":" ");
}
return 0;
}
/* 测试点5、7测试样例,输出的桌子要为 0 0 1 而不是 1 0 0
1
08:00:00 20 1
3 1
3
*/
K个球桌(编号1~K),但球桌都满的时候,有一条等待队伍
有VIP的存在,所以在输入的最后给了VIP球桌的编号,当有VIP球桌开放的时候,
队伍里面的第一个VIP将会无视他在队伍的顺序,直接进入该VIP球桌;
如果没有VIP的话或VIP球桌那就按正常形式。
营业时间为:8点~21点
统计队伍中每个人的等待时间 和 每个球桌在这一天共招待了几对球友
输出每对球友的到达时间 开始打球的时间
无事做将代码缩短成了100行
#include<bits/stdc++.h>
using namespace std;
int N, K, M;
const int OpenTime = 28800;
const int CloseTime = 75600;
bool VipIsIn[10000] = {
false};
struct Player {
int arrvTime, playTime, waitTime, isVipPly, num;
Player(): arrvTime(OpenTime), playTime(0), waitTime(0),isVipPly(false), num(0xffffff) {
}
bool operator<(Player b)const{
return this->arrvTime < b.arrvTime; }
}player[10000];
struct Table {
int EndTime, isVipTbl, serveNum;
Table():EndTime(OpenTime), isVipTbl(false), serveNum(0) {
}
}table[101];
int main() {
cin >> N;
int realN = 0;
for(int i = 0;i < N;++i) {
int h, m, s, playT, isVip;
scanf("%d:%d:%d %d %d\n", &h, &m, &s, &playT, &isVip);
int arvT = (h*60 + m)*60 + s;
if(arvT < CloseTime){
player[realN].arrvTime = arvT;
player[realN].playTime = playT > 120 ? 120*60 : playT*60;
player[realN].isVipPly = isVip;
realN++;
}
}
N = realN;
cin >> K >> M;
for(int i = 0;i < M;++i) {
int tableID;
cin >> tableID;
table[tableID].isVipTbl = true;
}
sort(player, player+N);
queue<int> VIPS;
for(int i = 0;i < N;++i)
if(player[i].isVipPly)
VIPS.push(i);
int numb = 0;
for(int i = 0;i < N;++i) {
Player &Pl = player[i];
Player &vipPl = player[VIPS.front()];
int minTableID = -1, minEndTime = 0xffffff;
for(int j = 1;j <= K;++j) {
if(table[j].EndTime < minEndTime){
minTableID = j;
minEndTime = table[j].EndTime;
}
}
if(table[minTableID].EndTime >= CloseTime) {
Pl.num = 0xffffff;
break;
}
if(Pl.isVipPly && !table[minTableID].isVipTbl){
for(int j = 1; j <= K; j++){
if(Pl.arrvTime >= table[j].EndTime && table[j].isVipTbl){
minTableID = j;
break;
}
}
}
Table &Tb = table[minTableID];
if(VipIsIn[i]) continue;
if(vipPl.arrvTime < Tb.EndTime && Pl.arrvTime < Tb.EndTime && Tb.isVipTbl && !VIPS.empty()) {
vipPl.waitTime = (Tb.EndTime - vipPl.arrvTime);
Tb.EndTime += vipPl.playTime;
VipIsIn[VIPS.front()] = true;
vipPl.num = numb;
i--;
VIPS.pop();
} else {
if(Pl.arrvTime < Tb.EndTime) {
Pl.waitTime = (Tb.EndTime - Pl.arrvTime);
Tb.EndTime += Pl.playTime;
} else {
Tb.EndTime = Pl.arrvTime + Pl.playTime;
}
if(Pl.isVipPly){
VipIsIn[i] = true;
VIPS.pop();
}
Pl.num = numb;
}
numb++;
Tb.serveNum++;
}
sort(player, player+N, [](Player a, Player b){
return a.num < b.num;});
for(Player &Pl : player) {
if(Pl.num == 0xffffff) continue;
int ah = Pl.arrvTime/3600, am = Pl.arrvTime%3600/60, as = Pl.arrvTime%60, bh = (Pl.arrvTime+Pl.waitTime)/3600, bm = (Pl.arrvTime+Pl.waitTime)%3600/60, bs = (Pl.arrvTime+Pl.waitTime)%60;
Pl.waitTime = Pl.waitTime/60 + (Pl.waitTime%60 >= 30);
printf("%02d:%02d:%02d %02d:%02d:%02d %d\n",ah,am,as,bh,bm,bs,Pl.waitTime);
}
for(int i = 1;i <= K;++i) cout << table[i].serveNum << (i == K?"\n":" ");
return 0;
}