[PAT解题报告] Table Tennis
超级麻烦的模拟题。
有乒乓球桌子,每个人来了要说玩多长时间。桌子有普通桌子和VIP桌子。可以认为普通人和VIP在两个不同的队列里,有空桌的话VIP优先,并且VIP优先进入VIP的桌子。还有一些限制每个人不能玩超过两个小时而且没有VIP的时候,普通人也可以用VIP的桌子,VIP如果没有VIP桌子可以用普通人的桌子——总之很多规则,最后看一下每个人玩多久,每个桌子支持了多少人。
我们用事件驱动的方法。
事件包括 :
(1) 时间
(2) 人的id或者桌子的id
(3) 人的id表示人来了,桌子的id表示桌子腾空
我们看一下如何处理这些事件
我们把所有事件按照时间顺序排序,并且同一时间里优先考虑先来人,这样腾出桌子后,能使用这个桌子的人已经在等着呢。
(1) 腾空桌子比较简单
(1.1)把桌子加入到对应集合(VIP桌子和非VIP桌子)
(1.2)考虑是否能进人, 如果有VIP等并且有VIP的桌子,就给VIP分配VIP的桌子(编号最小的)
(1.3) 至此,要么没有VIP的桌子,要么没有VIP人,那么所有人“平等”分配桌子
(2) VIP人来
(2.1) 有VIP的桌子,就给他分配VIP的桌子
(2.2) 没有VIP的桌子,有普通的桌子,给他分配普通桌子
(2.3) 桌子全满,进入VIP等候队列
(3)普通人来
(3.1)
有空桌子(无论是否是VIP桌子)就分配给他——注意这是题目的坑所在,普通人只要有桌子,就可以分配给他一个编号最小的桌子,因为有空桌子一定没有人在等
(3.2) 进入普通的等候队列
关于(1.3)如何平等?
我们可以支持选一个来的最早的人,尽管有两种队列,我们从VIP人和普通人里选一个来得最早的就可以了——题目说没有两个人同时到
如何选一个编号最小的桌子? 和选人一样,从两种桌子集合里面选一个最小的就可以了。
至于集合,可以用set<int>来做,begin就是最小的,我们可以存两种空桌子的id,
还有两种排队的人的id,注意存人的id,主要要存他什么时候来的,所以要存pair<int,int>
表示来的时间和id,因为第一维才是最重要的。
关于 分配桌子后事件的变化,
一个人被分配了一张桌子,我们知道他玩的时间,自然知道他离开桌子的时间,所以我们在事件队列里加一个腾空桌子的事件。总之,就是每满足一个人,就计算他离开的时间加入事件队列。
所以事件是动态的,需要动态按照时间顺序排序,所以自然就用堆、优先队列这种数据结构,我用了优先队列。
time, id, time表示时间,id和类型。如果类型是0,表示id是腾空桌子的id,否则type是1表示id是来的人的id。
还有一个坑就是每个人玩的时间不要超过两个小时——但是输入请求有超过两个小时的,我们需要自己把它变为两个小时(申请玩的时间和120分钟取最小值)。
代码很长: 关键还是要理解上述描述的,选人,选桌,处理时间,处理VIP的过程,理解起来就方便了。
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <set>
using namespace std;
const int N = 10004;
const int M = 102;
const int close = 3600 * 21;
struct node {
int time;
int id;
int type;
}; // type = 0, table free, 1 person come
bool operator<(const node &a,const node &b) {
if (a.time > b.time) {
return true;
}
if (a.time < b.time) {
return false;
}
return (a.time > b.time) || ((a.time == b.time) && (a.type < b.type));
}
int num[M];
int play[N];
bool isvipperson[N];
bool isviptable[M];
set<int> ordtable;
set<int> viptable;
set<pair<int,int> > vipperson;
set<pair<int,int> > ordperson;
priority_queue<node> affair;
int gettable() {
int r;
if (ordtable.empty()) {
r = *viptable.begin();
viptable.erase(viptable.begin());
return r;
}
if (viptable.empty()) {
r = *ordtable.begin();
ordtable.erase(ordtable.begin());
return r;
}
if (*ordtable.begin() < *viptable.begin()) {
r = *ordtable.begin();
ordtable.erase(ordtable.begin());
}
else {
r = *viptable.begin();
viptable.erase(viptable.begin());
}
return r;
}
pair<int,int> getperson() {
pair<int,int> r;
if (ordperson.empty()) {
r = *vipperson.begin();
vipperson.erase(vipperson.begin());
return r;
}
if (vipperson.empty()) {
r = *ordperson.begin();
ordperson.erase(ordperson.begin());
return r;
}
if (ordperson.begin()->first < vipperson.begin()->first) {
r = *ordperson.begin();
ordperson.erase(ordperson.begin());
}
else {
r = *vipperson.begin();
vipperson.erase(vipperson.begin());
}
return r;
}
void freetable(int x) {
if (isviptable[x]) {
viptable.insert(x);
}
else {
ordtable.insert(x);
}
}
void print(int x,int y) {
printf("%02d:%02d:%02d %02d:%02d:%02d %d\n",x / 3600, x % 3600 / 60, x % 60, y / 3600, y % 3600 / 60, y % 60, (y - x + 30) / 60);
}
int main() {
int n;
node temp;
scanf("%d",&n);
for (int i = 0; i < n; ++i) {
int x;
int hh,mm,ss;
scanf("%d:%d:%d %d%d",&hh,&mm,&ss,&play[i],&x);
isvipperson[i] = x;
temp.id = i;
temp.time = hh * 3600 + mm * 60 + ss;
temp.type = 1;
play[i] = min(play[i], 120);
play[i] *= 60;
affair.push(temp);
}
int a;
for (scanf("%d%d",&n,&a);a;--a) {
int x;
scanf("%d",&x);
isviptable[--x] = true;
viptable.insert(x);
}
for (int i = 0; i < n; ++i) {
if (!isviptable[i]) {
ordtable.insert(i);
}
}
while (!affair.empty()) {
temp = affair.top();
affair.pop();
int now = temp.time;
if (now >= close) {
break;
}
if (temp.type == 0) {
freetable(temp.id);
while ((!affair.empty()) && (affair.top().type == 0) && (affair.top().time == now)) {
freetable(affair.top().id);
affair.pop();
}
while ((!viptable.empty()) && (!vipperson.empty())) {
temp.time = now + vipperson.begin()->second;
temp.type = 0;
++num[temp.id = *viptable.begin()];
print(vipperson.begin()->first, now);
affair.push(temp);
viptable.erase(viptable.begin());
vipperson.erase(vipperson.begin());
}
while (((!ordperson.empty()) || (!vipperson.empty())) && ((!ordtable.empty()) || (!viptable.empty()))) {
pair<int,int> g = getperson();
temp.time = now + g.second;
temp.type = 0;
++num[temp.id = gettable()];
print(g.first,now);
affair.push(temp);
}
}
else if (isvipperson[temp.id]) {
if (!viptable.empty()) {
temp.time = now + play[temp.id];
print(now, now);
temp.type = 0;
++num[temp.id = *viptable.begin()];
affair.push(temp);
viptable.erase(viptable.begin());
}
else if (!ordtable.empty()) {
temp.time = now + play[temp.id];
print(now, now);
temp.type = 0;
++num[temp.id = *ordtable.begin()];
affair.push(temp);
ordtable.erase(ordtable.begin());
}
else {
vipperson.insert(make_pair(now, play[temp.id]));
}
}
else if ((!viptable.empty()) || (!ordtable.empty())) {
temp.time = now + play[temp.id];
print(now, now);
temp.type = 0;
++num[temp.id = gettable()];
affair.push(temp);
}
else {
ordperson.insert(make_pair(now, play[temp.id]));
}
}
for (int i = 0; i < n; ++i) {
if (i) {
putchar(' ');
}
printf("%d",num[i]);
}
puts("");
return 0;
}
原题链接: http://www.patest.cn/contests/pat-a-practise/1026
