PAT A 1026 Table Tennis 解题报告
还不熟悉markdown语法,就先不在意格式了。
刷了一个多月的PAT,第一篇解题报告就献给A1026这个对我而言非常复杂的模拟题吧。
题目的主要设定有以下几点:
(1) 玩的时间不能超过2h。
(2) 优先选择序号小的空桌。
(3) 在21:00之后(含21:00)还没玩上的玩家不需要输出。
(4) 玩家有是否vip之分,桌子也有是否vip之分。vip玩家优先选择序号小的vip空桌。
(5) 当vip玩家和非vip玩家都在排队,且有vip桌子空出时,vip玩家优先,并选择空出的vip桌子。如果是非vip桌子空出,那么仍按照到达时间顺序优先。
解题思路:我个人想出的解题思路不是很好,代码也非常冗长,但还是记录一下表示纪念(好不容易ac了)。
首先很正常的想到根据到达时间顺序将玩家进行排序。
由于有设定(5):“排队时vip可以插队”的存在, 不能简单按照到达时间顺序对玩家进行一个一个的处理,而要考虑到非vip玩家和vip玩家都在排队这一情况。考虑这一情况的方法是将vip玩家和非vip玩家分开,分别按到达时间排序,并与所有桌子中最小的空出时间比较。
使用vector<player> isVip, notVip来记录两种玩家,并按到达时间顺序排序。之后,一个一个进行处理。可以使用两个队列,每次处理完 pop 一个,循环终止条件是两个队列都空。我这里用的是vector, 每次处理完将对应组的下标++,初始时对应组的下标都是0, 表示当前处理的元素的位置是队首。 循环终止条件是已经处理的人数 cnt 等于总人数N。然后就是循环处理:
step1: 遍历所有桌子,找到最小的空出时间 minTime, 以及空出时间是minTime的最小序号桌子 i 和最小序号vip桌子 j , j 的初值设为 -1。
step2: 取 isVip 和 notVip 的对应下标指向元素, 记为 firstVip 和 firstNotVip。
step3: 根据 firstVip 和 firstNotVip 的到达时间 与 minTime 的大小关系,分为以下四种情况:
- (1) firstVip 的到达时间和 firstNotVip 的到达时间都小于等于 minTime。说明firstVip 和 firstNotVip 之前都在排队等待空桌。这时再根据空出桌子的情况进一步细分:
- 如果 j >-1, 说明有vip桌子空出,那么直接将firstVip分配到该桌子,更新桌子的空出时间, cnt++, vip组下标++,这一轮循环结束。
- 如果没有vip桌子空出,那么根据 firstVip 和 firstNotVip 的到达顺序,将桌子 i 分配给对应先到者,更新桌子的空出时间, cnt++, 先到者所在组的下标++,这一轮循环结束。
- (2) firstVip 的到达时间 小于等于minTime, firstNotVip的到达时间大于minTime, 说明 firstVip 在排队,并且要给 firstVip 分配空桌, 如果 j > -1, 说明有vip桌子空出,将firstVip分配到桌子 j , 否则将firstVip分配到桌子 i 。更新桌子的空出时间, cnt++, vip组下标++, 这一轮循环结束。
- (3) firstVip 的到达时间大于minTime, firstNotVip 的到达时间小于 minTime, 说明firstNotVip 在排队, 直接将firstNotVip 分配到桌子 i , 更新桌子的空出时间, cnt++, notvip组下标++, 这一轮循环结束。
- (4) firstVip 和 firstNotVip 的到达时间都大于 minTime, 那么为先到者分配最小序号空桌。但是这时需要注意桌子 i 可能不是最小序号的空出桌子了,因为其他桌也可能已经空出,只是空出时间不是minTime而已。这里的最小序号空出桌子需要根据先到者的到达时间重新遍历所有桌子来寻找。同时,如果先到者是vip,还需要寻找是否有空出的vip桌子,如果有就分配到vip桌。 最后更新桌子的空出时间,cnt++, 先到者所在组下标++, 这一轮循环结束。
需要注意的是用这种思路,需要在 isVip 和 notVip两个vector或队列的末尾加上一个到达时间24:00:00的无效元素,否则处理完某组的最后一个有效元素后,下标会越界,加上之后不影响原思路并且防止了越界。
最后就是输出结果了,注意等待时间需要四舍五入用round函数再强制转换成 int 就好。
根据这个思路写的代码非常冗长,也没有用到任何数据结构(虽然这题看起来很像是要用优先队列,奈何太菜了)。还没有观摩其他简洁的解法,将来有时间再补充到这篇报告里。
以下是我的代码,非常冗长:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
int timeToSec(int h, int m, int s)
{
return h * 3600 + m * 60 + s;
}
void secToTime(int sec)
{
int h = sec / 3600, m = sec % 3600 / 60, s = sec %3600 %60;
printf("%02d:%02d:%02d ", h, m, s);
}
struct player
{
int arriveTime;
int playTime;
int startPlayTime;
player(int _arriveTime, int _playTime, int _isVIP)
{
arriveTime = _arriveTime;
startPlayTime = 0x7FFFFFFF;
playTime = _playTime;
}
player()
{
}
};
bool cmpPlayer(player a, player b)
{
return a.arriveTime < b.arriveTime;
}
struct table
{
int index;
int endTime;
int serveNum;
int isVIP;
table()
{
endTime = timeToSec(8,0,0);
serveNum = 0;
isVIP = 0;
}
};
int waitTime(int arriveTime, int startTime)
{
return (int)round((startTime - arriveTime) / 60.0);
}
vector<player> notVip, isVip, vp;
int main() {
int N;
cin >> N;
int cnt = 0, ptrIsVip = 0, ptrNotVip = 0;
for (int i = 0; i < N; ++i)
{
int h, m, s, p, isvip;
scanf("%d:%d:%d %d %d", &h, &m, &s, &p, &isvip);
if(p > 120) p = 120;
if(isvip) isVip.push_back(player(timeToSec(h, m, s), p*60, isvip));
else notVip.push_back(player(timeToSec(h, m, s), p*60, isvip));
}
int K, M;
cin >> K >> M;
vector<table> tables;
tables.resize(K);
for (int i = 0; i < K; ++i)
{
tables[i].index = i;
}
for (int i = 0; i < M; ++i)
{
int num;
scanf("%d", &num);
tables[num-1].isVIP = 1;
}
isVip.push_back(player(24 * 3600, 0, 1));
notVip.push_back(player(24 * 3600, 0, 0));
sort(isVip.begin(), isVip.end(), cmpPlayer);
sort(notVip.begin(), notVip.end(), cmpPlayer);
while(cnt < N && ptrIsVip < isVip.size() && ptrNotVip < notVip.size())
{
vector<table> emptyTable;
int minTime = 0x7FFFFFF;
for (int i = 0; i < K; ++i)
{
if(tables[i].endTime < minTime)
{
minTime = tables[i].endTime;
emptyTable.clear();
emptyTable.push_back(tables[i]);
}
else if(tables[i].endTime == minTime)
{
emptyTable.push_back(tables[i]);
}
}
int firstEmptyTable = emptyTable[0].index;
bool vipTableEmpty = 0;
int firstEmptyVipTable = 0;
for (int j = 0; j < emptyTable.size(); ++j)
{
if(emptyTable[j].isVIP == 1)
{
vipTableEmpty = 1;
firstEmptyVipTable = emptyTable[j].index;
break;
}
}
player &firstVip = isVip[ptrIsVip];
player &firstNotVip = notVip[ptrNotVip];
if(firstVip.arriveTime <= minTime && firstNotVip.arriveTime <= minTime)
{
if(vipTableEmpty == 1)
{
firstVip.startPlayTime = minTime;
if(firstVip.startPlayTime < 21 * 3600)
{
tables[firstEmptyVipTable].endTime = minTime + firstVip.playTime;
tables[firstEmptyVipTable].serveNum++;
vp.push_back(firstVip);
}
cnt++;
ptrIsVip++;
}
else
{
if(firstVip.arriveTime < firstNotVip.arriveTime)
{
firstVip.startPlayTime = minTime;
if(firstVip.startPlayTime < 21 * 3600)
{
tables[firstEmptyTable].endTime = minTime + firstVip.playTime;
tables[firstEmptyTable].serveNum++;
vp.push_back(firstVip);
}
cnt++;
ptrIsVip++;
}
else
{
firstNotVip.startPlayTime = minTime;
if(firstNotVip.startPlayTime < 21 * 3600)
{
tables[firstEmptyTable].endTime = minTime + firstNotVip.playTime;
tables[firstEmptyTable].serveNum++;
vp.push_back(firstNotVip);
}
cnt++;
ptrNotVip++;
}
}
}
else if(firstVip.arriveTime > minTime && firstNotVip.arriveTime <= minTime)
{
firstNotVip.startPlayTime = minTime;
if(firstNotVip.startPlayTime < 21 * 3600)
{
tables[firstEmptyTable].endTime = minTime + firstNotVip.playTime;
tables[firstEmptyTable].serveNum++;
vp.push_back(firstNotVip);
}
cnt++;
ptrNotVip++;
}
else if(firstVip.arriveTime <= minTime && firstNotVip.arriveTime > minTime)
{
firstVip.startPlayTime = minTime;
if(firstVip.startPlayTime < 21 * 3600)
{
if(vipTableEmpty == 1) firstEmptyTable = firstEmptyVipTable;
tables[firstEmptyTable].endTime = minTime + firstVip.playTime;
tables[firstEmptyTable].serveNum++;
vp.push_back(firstVip);
}
cnt++;
ptrIsVip++;
}
else if(firstVip.arriveTime > minTime && firstNotVip.arriveTime > minTime)
{
if(firstVip.arriveTime < firstNotVip.arriveTime)
{
int firstEmptyVipTableTmp = -1;
for (int i = 0; i < K; ++i)
{
if(tables[i].endTime <= firstVip.arriveTime)
{
firstEmptyTable = i;
break;
}
}
for (int i = 0; i < K; ++i)
{
if(tables[i].endTime <= firstVip.arriveTime && tables[i].isVIP == 1)
{
firstEmptyVipTableTmp = i;
break;
}
}
if(firstEmptyVipTableTmp > -1) firstEmptyTable = firstEmptyVipTableTmp;
firstVip.startPlayTime = firstVip.arriveTime;
if(firstVip.startPlayTime < 21 * 3600)
{
tables[firstEmptyTable].endTime = firstVip.startPlayTime + firstVip.playTime;
tables[firstEmptyTable].serveNum++;
vp.push_back(firstVip);
}
cnt++;
ptrIsVip++;
}
else
{
for (int i = 0; i < K; ++i)
{
if(tables[i].endTime <= firstNotVip.arriveTime)
{
firstEmptyTable = i;
break;
}
}
firstNotVip.startPlayTime = firstNotVip.arriveTime;
if(firstNotVip.startPlayTime < 21 * 3600)
{
tables[firstEmptyTable].endTime = firstNotVip.startPlayTime + firstNotVip.playTime;
tables[firstEmptyTable].serveNum++;
vp.push_back(firstNotVip);
}
cnt++;
ptrNotVip++;
}
}
}
for (int i = 0; i < vp.size(); ++i)
{
int arriveTime = vp[i].arriveTime, startTime = vp[i].startPlayTime;
secToTime(arriveTime);
secToTime(startTime);
printf("%d\n", waitTime(arriveTime, startTime));
}
for (int i = 0; i < K; ++i)
{
printf("%d", tables[i].serveNum);
if(i < K - 1) printf(" ");
}
return 0;
}