浙大 PAT Advanced level 1026. Table Tennis (30)

来源:互联网 发布:linux shell 数值比较 编辑:程序博客网 时间:2024/06/05 18:51
A table tennis club has N tables available to the public. The tables are numbered from 1 to N. For any pair of players, if there are some tables open when they arrive, they will be assigned to the available table with the smallest number. If all the tables are occupied, they will have to wait in a queue. It is assumed that every pair of players can play for at most 2 hours.

Your job is to count for everyone in queue their waiting time, and for each table the number of players it has served for the day.

One thing that makes this procedure a bit complicated is that the club reserves some tables for their VIP members. When a VIP table is open, the first VIP pair in the queue will have the priviledge to take it. However, if there is no VIP in the queue, the next pair of players can take it. On the other hand, if when it is the turn of a VIP pair, yet no VIP table is available, they can be assigned as any ordinary players.

Input Specification:

Each input file contains one test case. For each case, the first line contains an integer N (<=10000) - the total number of pairs of players. Then N lines follow, each contains 2 times and a VIP tag: HH:MM:SS - the arriving time, P - the playing time in minutes of a pair of players, and tag - which is 1 if they hold a VIP card, or 0 if not. It is guaranteed that the arriving time is between 08:00:00 and 21:00:00 while the club is open. It is assumed that no two customers arrives at the same time. Following the players' info, there are 2 positive integers: K (<=100) - the number of tables, and M (< K) - the number of VIP tables. The last line contains M table numbers.

Output Specification:

For each test case, first print the arriving time, serving time and the waiting time for each pair of players in the format shown by the sample. Then print in a line the number of players served by each table. Notice that the output must be listed in chronological order of the serving time. The waiting time must be rounded up to an integer minute(s). If one cannot get a table before the closing time, their information must NOT be printed.

Sample Input:
9
20:52:00 10 0
08:00:00 20 0
08:02:00 30 0
20:51:00 10 0
08:10:00 5 0
08:12:00 10 1
20:50:00 10 0
08:01:30 15 1
20:53:00 10 1
3 1
2
Sample Output:
08:00:00 08:00:00 0
08:01:30 08:01:30 0
08:02:00 08:02:00 0
08:12:00 08:16:30 5
08:10:00 08:20:00 10
20:50:00 20:50:00 0
20:51:00 20:51:00 0
20:52:00 20:52:00 0

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;}


0 0