[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



全部评论
你这种事件驱动的思想真是太强大了。。。 这样就可以掌握一系列的问题的处理方法了。
点赞 回复 分享
发布于 2015-10-31 20:54
仔细研读了,谢谢lz~~
点赞 回复 分享
发布于 2016-03-25 22:40
因为120分钟卡了半小时,气
点赞 回复 分享
发布于 2017-09-25 20:54

相关推荐

10-24 11:10
山西大学 Java
若梦难了:哥们,面试挂是很正常的。我大中厂终面挂,加起来快10次了,继续努力吧。
点赞 评论 收藏
分享
面试摇了我吧:啊哈哈面试提前五个小时发,点击不能参加就是放弃
点赞 评论 收藏
分享
2 收藏 评论
分享
牛客网
牛客企业服务