3 3 2
非常复杂的题目,解决之后再碰到其它模拟题基本上都可以手到擒来。
用来学习“事件驱动”思想的好题目。
http://www.nowcoder.com/discuss/391
超级麻烦的模拟题。
有乒乓球桌子,每个人来了要说玩多长时间。桌子有普通桌子和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的过程,理解起来就方便了。
/* http://www.nowcoder.com/discuss/391 超级麻烦的模拟题。 有乒乓球桌子,每个人来了要说玩多长时间。桌子有普通桌子和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 <iostream> #include <queue> #include <stdio.h> #include <vector> #include <set> using namespace std; const int close_time = 21*3600; int N, K, M; vector<int> play_time; /* play time of each pair*/ vector<bool> is_vip_player; vector<bool> is_vip_table; set<int> ord_table; /* table index*/ set<int> vip_table; /* table index*/ set< pair<int, int> > vip_player; /* arrive_time , play_time*/ set< pair<int, int> > ord_player; /* arrive_time , play_time*/ vector<int> nums; /* nums of pairs played on each table*/ typedef struct node { int time; int id; int type; /* 0->table free, 1->people come*/ }node; priority_queue<node> affairs; bool operator<(const node &A, const node &B) { if (A.time != B.time) { return A.time > B.time; } else { return A.type < B.type; } } void freeTable(int index) { if (is_vip_table[index]) { vip_table.insert(index); } else { ord_table.insert(index); } } void printTime(int arrive_time, int serve_time) { printf("%02d:%02d:%02d %02d:%02d:%02d ", arrive_time/3600, arrive_time/60%60, arrive_time%60, serve_time/3600, serve_time/60%60, serve_time%60); printf("%d\n", (serve_time-arrive_time+30)/60); } pair<int, int> getPlayer() { pair<int, int> ret; if (vip_player.empty()) { ret = *ord_player.begin(); ord_player.erase(ord_player.begin()); return ret; } if (ord_player.empty()) { ret = *vip_player.begin(); vip_player.erase(vip_player.begin()); return ret; } if (ord_player.begin()->first < vip_player.begin()->first) { ret = *ord_player.begin(); ord_player.erase(ord_player.begin()); } else { ret = *vip_player.begin(); vip_player.erase(vip_player.begin()); } return ret; } int getTable() { int ret; if (vip_table.empty()) { ret = *ord_table.begin(); ord_table.erase(ord_table.begin()); return ret; } if (ord_table.empty()) { ret = *vip_table.begin(); vip_table.erase(vip_table.begin()); return ret; } if (*vip_table.begin() < *ord_table.begin()) { ret = *vip_table.begin(); vip_table.erase(vip_table.begin()); } else { ret = *ord_table.begin(); ord_table.erase(ord_table.begin()); } return ret; } int main() { int hh, mm, ss, viptag, index, nowtime; node temp; pair<int, int> tplayer; cin >> N; play_time.resize(N); is_vip_player.resize(N); for (int i = 0; i != N; ++i) { scanf("%d:%d:%d %d %d", &hh, &mm, &ss, &play_time[i], &viptag); is_vip_player[i] = (bool)viptag; play_time[i] = 60 * min(play_time[i], 120); temp.time = hh*3600 + mm*60 + ss; temp.id = i; temp.type = 1; affairs.push(temp); } cin >> K >> M; nums.resize(K); is_vip_table.resize(K); for (int i = 0; i != M; ++i) { cin >> index; is_vip_table[--index] = true; } for (int i = 0; i != K; ++i) { if (is_vip_table[i]) { vip_table.insert(i); } else { ord_table.insert(i); } } while (!affairs.empty()) { temp = affairs.top(); affairs.pop(); nowtime = temp.time; if (nowtime >= close_time) { break; } if (0 == temp.type) { freeTable(temp.id); /* 多个桌子可能同时释放*/ while (!affairs.empty() && affairs.top().type == 0 && affairs.top().time == nowtime) { freeTable(affairs.top().id); affairs.pop(); } while (!vip_table.empty() && !vip_player.empty()) { temp.time = nowtime + vip_player.begin()->second; temp.type = 0; temp.id = *vip_table.begin(); ++nums[temp.id]; printTime(vip_player.begin()->first, nowtime); affairs.push(temp); vip_table.erase(vip_table.begin()); vip_player.erase(vip_player.begin()); } while ((!ord_player.empty() || !vip_player.empty()) && (!ord_table.empty() || !vip_table.empty())) { tplayer = getPlayer(); temp.time = nowtime + tplayer.second; temp.type = 0; temp.id = getTable(); ++nums[temp.id]; printTime(tplayer.first, nowtime); affairs.push(temp); } } else { if (is_vip_player[temp.id]) { if (!vip_table.empty()) { temp.time = nowtime + play_time[temp.id]; printTime(nowtime, nowtime); temp.type = 0; temp.id = *vip_table.begin(); ++nums[temp.id]; affairs.push(temp); vip_table.erase(vip_table.begin()); } else { if (!ord_table.empty()) { temp.time = nowtime + play_time[temp.id]; printTime(nowtime, nowtime); temp.type = 0; temp.id = *ord_table.begin(); ++nums[temp.id]; affairs.push(temp); ord_table.erase(ord_table.begin()); } else { vip_player.insert(make_pair(nowtime, play_time[temp.id])); } } } else { if (!vip_table.empty() || !ord_table.empty()) { temp.time = nowtime + play_time[temp.id]; printTime(nowtime, nowtime); temp.type = 0; temp.id = getTable(); ++nums[temp.id]; affairs.push(temp); } else { ord_player.insert(make_pair(nowtime, play_time[temp.id])); } } } } for (unsigned int i = 0; i != nums.size(); ++i) { if (0 != i) { cout << ' '; } cout << nums[i]; } cout << endl; return 0; }
浙大 PAT Advanced level 1026. Table Tennis (30)
原文:http://blog.csdn.net/fanxingzju/article/details/51397471