【PAT】1026. Table Tennis (30)【超大型模拟题】

题目描述

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.

翻译:一个乒乓球俱乐部有N张公共球桌。这些桌子被标记为1-N。对于每队乒乓球选手,如果他们到达时有一些球桌空闲的话,他们将会选择编号最小的桌子。如果所有桌子都有人,则排队等待。假设所有运动员最多玩2小时。
你的任务是计算出所有队列里的人的等待时间,和每张桌子当天服务的(一对)运动员数。
俱乐部设置了一些桌子给他它们的VIP成员使用,这让过程变得有些复杂。当一个VIP台子空闲时,第一对在队列里的VIP运动员将优先使用它。但是如果没有VIP在队列里,那么接下来的一对运动员可以使用它。另一方面,如果轮到一对VIP运动员时没有VIP桌了,他们会向普通运动员一样选择。

INPUT FORMAT

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.

翻译:每个输入文件包含一组测试数据。对于每组输入数据,第一行包括一个正整数N(<=10000) -运动员的总对数。接下来的N行,每行包括2个时间和一个VIP标记: HH:MM:SS-到达时间,P-运动时间(分钟),VIP标记-如果是1代表有VIP卡,0代表没有。数据保证到达时间为 08:00:00 and 21:00:00 (最大的谎言),即俱乐部开放时间。假设没有一对运动员同时到达。在运动员的信息后面,是两个正整数K (<=100) - 桌子数,和M (< K) - VIP桌子数。最后一行包括M个(VIP)桌子编号。

OUTPUT FORMAT

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


解题思路

这道题真的是一步一个坑,一开始当成是之前的银行排队,欢天喜地写了个代码,结果就过了2-3个。。。然后仔细读题,发现了一大堆坑。。没列的坑都属于比较好看出来的哈。
1.客户永远挑编号最小的桌子,而不是最早空着的。
2.烦人的vip在有空桌时先挑编号最小的vip桌(万恶之源)
3.等待时间四舍五入
4.训练时间最多2小时,不是条件帮你限制到2小时以内,是你自己控制(我曹,这么简单的点真的没想到啊。关键是这个点考的感觉没意义,就是练翻译)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<algorithm>
#define INF 99999999
using namespace std;
struct Time{
    int h,m,s;
    Time(){
        h=0,m=0,s=0;
    }
    Time(int h,int m,int s):h(h),m(m),s(s){}
    bool operator<(const Time &a)const{
        return h==a.h?(m==a.m?s<a.s:m<a.m):h<a.h;
    }
    bool operator>(const Time &a)const{
        return h==a.h?(m==a.m?s>a.s:m>a.m):h>a.h;
    }
    bool operator==(const Time &a)const{
        return (h==a.h)&&(m==a.m)&&(s==a.s);
    }
    int operator-(const Time &a)const{
        int temp=0;
        temp=temp+(h-a.h)*3600+(m-a.m)*60+s-a.s+30;
        temp=temp/60;
        return temp;
    }
    Time plus(int a){//返回加上a min后的时间 
        m+=a;
        if(m>=60){
            h+=m/60;
            m%=60;
        }
        return Time(h,m,s);
    }
    bool limit(){//判断是否超21点 
        if(h>=21)return true;
        return false;
    }
};
struct table{
    Time tim;
    int num;
    int vip;
    table(Time t,int num,int V):tim(t),num(num),vip(V){}
    bool operator<(const table &a)const{
        return tim==a.tim?num>a.num:tim>a.tim;
    }
}; 
struct player{
    Time come,play;
    int cost;
    player():come(Time(25,0,0)),play(Time(25,0,0)),cost(-1){}
    player(Time a,int c):come(a),play(Time()),cost(c){}
    bool operator<(const player &a)const{
        return come>a.come;
    }
};
struct tplay{//就是player,只不过按照上桌时间保存 
    player p;
    tplay(player p):p(p){}
    bool operator<(const tplay &a)const{
        return p.play>a.p.play;
    }
    int min(){
        return p.play-p.come;
    }
};
priority_queue<player>p[2];
priority_queue<tplay>tp;
priority_queue<table>tb;
int N,K,M,v[110],ans[110];
Time tab[110];
int findTable(player p,int vip){//在有空桌的情况下进行挑选 
    int temp=0;
    for(int i=1;i<=K;i++){
        if(p.come>tab[i]||p.come==tab[i]){ 
            if(v[i]==1)return i; //如果是vip桌直接输出 
            if(vip==0)return i; //普通客户直接选最小的 
            if(temp==0)temp=i;  //保存最小的空桌,如果vip客户且没空vip桌输出 
        }
    }
    return temp;
} 
int main(){
    scanf("%d",&N);
    int h,m,s,cost,V;
    for(int i=0;i<N;i++){
        scanf("%d:%d:%d%d%d",&h,&m,&s,&cost,&V);
        if(cost>=120)cost=120;
        Time a(h,m,s); 
        p[V].push(player(a,cost)); 
    }
    scanf("%d%d",&K,&M);
    int a;
    for(int i=0;i<M;i++){
        scanf("%d",&a);
        v[a]=1;
    } 
    for(int i=1;i<=K;i++){
        tab[i]=Time(8,0,0);
        tb.push(table(Time(8,0,0),i,v[i]));
    }
    while(1){
        table tempTb=tb.top();
        if(tempTb.tim>tab[tempTb.num]||tempTb.tim<tab[tempTb.num]){tb.pop();continue;}
        if(tempTb.tim.limit()==true)break;
        player p0,p1;//一开始应该用个tempPlayer[2]保存的,后面代码可以简化 
        if(!p[0].empty()){ 
            player temp=p[0].top();
            if(temp.come.limit()==false)//如果在21:00之前才会计算 
            p0=p[0].top();
        }
        if(!p[1].empty()){
            player temp=p[1].top();
            if(temp.come.limit()==false)//如果在21:00之前才会计算 
            p1=p[1].top();
        }
        int flag;
        if(p0.come<p1.come)flag=0;
        else flag=1;
        if(p0.cost==-1&&p1.cost==-1)break;//如果队伍没人了,退出 
        if((tempTb.vip||flag==1)&&p1.come<tempTb.tim){//如果是vip桌子,并且有vip人员等排队 
            p1.play=tempTb.tim;
            tempTb.tim=tempTb.tim.plus(p1.cost);
            tab[tempTb.num]=tempTb.tim;
            ans[tempTb.num]++;
            tb.pop();
            tb.push(tempTb);
            tp.push(p1);
            p[1].pop();
            continue;
        }
        else if(flag==0&&p0.come<tempTb.tim){//不是vip并且有人排队 
            p0.play=tempTb.tim;
            tempTb.tim=tempTb.tim.plus(p0.cost);
            tab[tempTb.num]=tempTb.tim;
            ans[tempTb.num]++;
            tb.pop();
            tb.push(tempTb);
            tp.push(p0);
            p[0].pop();
            continue;
        }
        else if(flag==0){//如果有空桌并且为普通客户 
            p0.play=p0.come;
            int choose=findTable(p0,0);
//          printf("%d:%d:%d %d\n",p0.come.h,p0.come.m,p0.come.s,choose);
            ans[choose]++;
            tab[choose]=p0.come;
            tab[choose]=tab[choose].plus(p0.cost);
            tb.push(table(tab[choose],choose,v[choose]));
            tp.push(p0);
            p[0].pop();
            continue;
        }
        else if(flag==1){//如果有空桌并且是vip客户 
            p1.play=p1.come;
            int choose=findTable(p1,1);
//          printf("%d:%d:%d %d\n",p1.come.h,p1.come.m,p1.come.s,choose);
            ans[choose]++;
            tab[choose]=p1.come;
            tab[choose]=tab[choose].plus(p1.cost);
            tb.push(table(tab[choose],choose,v[choose]));
            tp.push(p1);
            p[1].pop();
            continue;
        }
    }
    while(!tp.empty()){
        tplay temp=tp.top();tp.pop();
        Time pre=temp.p.come,pro=temp.p.play;
        int co=temp.min();
        printf("%02d:%02d:%02d %02d:%02d:%02d %d\n",pre.h,pre.m,pre.s,pro.h,pro.m,pro.s,co);
    }
    for(int i=1;i<=K;i++){
        if(i==1)
        printf("%d",ans[i]);
        else
        printf(" %d",ans[i]);       
    }
    printf("\n");
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值