【PAT甲级 模拟 测试点0、3、4、5、7、8分析】1026 Table Tennis (30 分)

这篇文章帮我解决了测试点5、7
测试点分析都在代码注释里了

#include<bits/stdc++.h>
using namespace std;

int N, K, M; // 球友对的数量、球桌数、VIP球桌数
const int OpenTime = 28800;  // 开门时间 8点
const int CloseTime = 75600; // 关门时间 21点
struct Player {
    
    
    int arrvTime; // 球友到达时间
    int playTime; // 球友占用球桌的时间
    int waitTime; // 球友等待时间
    bool isVipPly;// 球友是不是vip
    int num;      // 球友的输出的编号
    Player(): arrvTime(OpenTime), playTime(0), waitTime(0),isVipPly(false), num(0xffffff) {
    
    }
};

struct Table {
    
    
    int EndTime;  // 上一对球友打完球离开该球桌的时间
    bool isVipTbl;// 是不是vip桌
    int serveNum; // 桌子招待过多少球友
    Table():EndTime(OpenTime), isVipTbl(false), serveNum(0) {
    
    }
};

int main() {
    
    
    Player player[10000];
    Table table[101];
    bool VipIsIn[10000] = {
    
    false}; // 记录当前VIP是否已被处理过,防止当前处理到的是之前已经服务过的的VIP

    cin >> N;
    int realN = 0; // 记录符合要求的输入数据(到达时间在21点之前的球友)
    for(int i = 0;i < N;++i) {
    
    
        // 输入:每队球友的到达时间、占用球桌的时间(最多不能超过两小时)、是否是VIP
        int h, m, s, playT, isVip;
        scanf("%d:%d:%d %d %d\n", &h, &m, &s, &playT, &isVip);
        int arvT = (h*60 + m)*60 + s; // 按照秒数记录player到达时间
        if(arvT < CloseTime){
    
     // 针对测试点3,到达时间刚好为21点,要舍去这个输入
            player[realN].arrvTime = arvT;
            player[realN].playTime = playT > 120 ? 120*60 : playT*60; // 针对测试点4,打球超过2小时的都要强制变成120分钟
            player[realN].isVipPly = isVip;
            realN++;
        }
    }
    N = realN; // 将N变成真正有效的player个数
    
	// 输入有关球桌的数据
    cin >> K >> M;
    for(int i = 0;i < M;++i) {
    
    
        int tableID;
        cin >> tableID;
        table[tableID].isVipTbl = true; // 标记vip桌
    }


    sort(player, player+N, [](Player &a, Player &b){
    
      // 按照到达时间排序
        return a.arrvTime < b.arrvTime;
    });
    queue<int> VIPS; // 将VIP按照到达时间放入一个单独的队列
    for(int i = 0;i < N;++i)
        if(player[i].isVipPly)
            VIPS.push(i);

	/*** 算法开始(太难了呀!!) ***/
    int numb = 0; // 记录球友开始打球的顺序
    for(int i = 0;i < N;++i) {
    
    
        // 如果当前选手i是已经被提前处理的VIP,那就不能处理要跳过
        if(VipIsIn[i]) continue;
        
        //找到最小结束时间的桌子
        int minTableID = -1;
        int minEndTime = 0xffffff;
        for(int j = 1;j <= K;++j) {
    
    
            if(table[j].EndTime < minEndTime){
    
    
                minTableID = j;
                minEndTime = table[j].EndTime;
            }
        }
        Player &Pl = player[i]; // 当前要处理的player的引用
        Player &vipPl = player[VIPS.front()]; // 当前队列中第一个vip的引用

        // 如果最早结束的桌子的结束时间超过了21点,那当前和后面到达的选手都不能处理输出
        if(table[minTableID].EndTime >= CloseTime) {
    
     // 测试点0、8(测试点8是等于号)
            Pl.num = 0xffffff; // 标记为无效,不能输出
            break; // 因为每个选手的num一开始就都初始化为0xffffff,所以可以直接break;否则要continue
        }
        
        // 测试点5、7:vip用户要选择第一张空闲的vip桌
        if(Pl.isVipPly && !table[minTableID].isVipTbl){
    
     // 当前选手是VIP选手,要选择空闲的普通桌子和VIP桌子中选择VIP桌子
            for(int j = 1; j <= K; j++){
    
     
                if(Pl.arrvTime >= table[j].EndTime && table[j].isVipTbl){
    
     //测试点7在这个等于号
                    minTableID = j; 
                    break;
                }
            }
        }
		
		/******* 终于找到了正确的桌子 *******/
        Table &Tb = table[minTableID]; 

        // 如果vip和非vip都需要等待,而且空出来的球桌是VIP球桌,那就让VIP优先
        if(vipPl.arrvTime < Tb.EndTime && Pl.arrvTime < Tb.EndTime &&
           Tb.isVipTbl && !VIPS.empty()) {
    
     // !VipIsIn[i]是防止当前处理到的是之前已经服务过的的VIP
            // 处理的是队伍中当前选手i的后面的VIP选手
            vipPl.waitTime = (Tb.EndTime - vipPl.arrvTime);
            Tb.EndTime += vipPl.playTime;
            VipIsIn[VIPS.front()] = true; // 记录该VIP已被服务过,防止后面遍历到他又处理一遍
            vipPl.num = numb; // 记录输出顺序
            i--; // 因为处理的是当前选手i后面的VIP选手,这一次的循环没有处理选手i,所以要i--抵消i++来停下处理当前选手i
            VIPS.pop(); // 处理完当前VIP了
            
        } else {
    
     // 当前选手不是的VIP选手 或者 是VIP选手但当成普通选手的VIP选手(空闲球桌不是VIP球桌)
            if(Pl.arrvTime < Tb.EndTime) {
    
     // 需要等待
                Pl.waitTime = (Tb.EndTime - Pl.arrvTime);
                Tb.EndTime += Pl.playTime;
            } else {
    
     // 不需要等待
                Tb.EndTime = Pl.arrvTime + Pl.playTime;
            }
            Pl.num = numb; // 记录输出顺序
            
            /* VIP选手没碰上VIP发挥作用的情况(也就是当前处理的选手是VIP但是把他当普通选手处理了
            所以要在VIP队列里删除他,并且标记该VIP为已经处理过) */
            if(Pl.isVipPly){
    
     // 这个超关键 
                VipIsIn[i] = true;
                VIPS.pop();
            }
        }
        numb++; // 因为有i--,所以用numb来标记输出顺序
        Tb.serveNum++; // 统计桌子招待选手数量
    }

    
    sort(player, player+N, [](Player &a, Player &b){
    
     // 按照记录的输出标记顺序来输出
        return a.num < b.num;
    });
    for(int i = 0;i < N;++i) {
    
    
        Player &Pl = player[i];
        if(Pl.num == 0xffffff) continue; // 超过21点才能打球的球友就不能输出了
        int ah = Pl.arrvTime/3600, am = Pl.arrvTime%3600/60, as = Pl.arrvTime%60;
        int bh = (Pl.arrvTime+Pl.waitTime)/3600, bm = (Pl.arrvTime+Pl.waitTime)%3600/60, bs = (Pl.arrvTime+Pl.waitTime)%60;
        // 等待的分钟数要四舍五入
        if(player[i].waitTime%60 >= 30) {
    
    
            player[i].waitTime = player[i].waitTime/60 + 1;
        } else {
    
    
            player[i].waitTime = player[i].waitTime/60;
        }
        printf("%02d:%02d:%02d %02d:%02d:%02d %d\n",ah,am,as,bh,bm,bs,player[i].waitTime);
    }
    for(int i = 1;i <= K;++i) {
    
    
        cout << table[i].serveNum << (i == K?"\n":" ");
    }
    
    return 0;
}

/* 测试点5、7测试样例,输出的桌子要为 0 0 1 而不是 1 0 0
1
08:00:00 20 1
3 1
3
*/

K个球桌(编号1~K),但球桌都满的时候,有一条等待队伍
有VIP的存在,所以在输入的最后给了VIP球桌的编号,当有VIP球桌开放的时候,
队伍里面的第一个VIP将会无视他在队伍的顺序,直接进入该VIP球桌;
如果没有VIP的话或VIP球桌那就按正常形式。

营业时间为:8点~21点

统计队伍中每个人的等待时间 和 每个球桌在这一天共招待了几对球友

输出每对球友的到达时间 开始打球的时间

无事做将代码缩短成了100行

#include<bits/stdc++.h>
using namespace std;

int N, K, M;
const int OpenTime = 28800;
const int CloseTime = 75600;
bool VipIsIn[10000] = {
    
    false};
struct Player {
    
    
    int arrvTime, playTime, waitTime, isVipPly, num;
    Player(): arrvTime(OpenTime), playTime(0), waitTime(0),isVipPly(false), num(0xffffff) {
    
    }
    bool operator<(Player b)const{
    
     return this->arrvTime < b.arrvTime; }
}player[10000];
struct Table {
    
    
    int EndTime, isVipTbl, serveNum; 
    Table():EndTime(OpenTime), isVipTbl(false), serveNum(0) {
    
    }
}table[101];

int main() {
    
    
    cin >> N;
    int realN = 0;
    for(int i = 0;i < N;++i) {
    
    
        int h, m, s, playT, isVip;
        scanf("%d:%d:%d %d %d\n", &h, &m, &s, &playT, &isVip);
        int arvT = (h*60 + m)*60 + s;
        if(arvT < CloseTime){
    
    
            player[realN].arrvTime = arvT;
            player[realN].playTime = playT > 120 ? 120*60 : playT*60;
            player[realN].isVipPly = isVip;
            realN++;
        }
    }
    N = realN;
    cin >> K >> M;
    for(int i = 0;i < M;++i) {
    
    
        int tableID;
        cin >> tableID;
        table[tableID].isVipTbl = true;
    }
    sort(player, player+N);
    queue<int> VIPS;
    for(int i = 0;i < N;++i)
        if(player[i].isVipPly)
            VIPS.push(i);

    int numb = 0;
    for(int i = 0;i < N;++i) {
    
    
        Player &Pl = player[i];
        Player &vipPl = player[VIPS.front()];
        int minTableID = -1, minEndTime = 0xffffff;
        for(int j = 1;j <= K;++j) {
    
    
            if(table[j].EndTime < minEndTime){
    
    
                minTableID = j;
                minEndTime = table[j].EndTime;
            }
        }
        if(table[minTableID].EndTime >= CloseTime) {
    
    
            Pl.num = 0xffffff;
            break;
        }
        if(Pl.isVipPly && !table[minTableID].isVipTbl){
    
    
            for(int j = 1; j <= K; j++){
    
     
                if(Pl.arrvTime >= table[j].EndTime && table[j].isVipTbl){
    
    
                    minTableID = j; 
                    break;
                }
            }
        }
        Table &Tb = table[minTableID]; 
        if(VipIsIn[i]) continue;
        if(vipPl.arrvTime < Tb.EndTime && Pl.arrvTime < Tb.EndTime && Tb.isVipTbl && !VIPS.empty()) {
    
    
            vipPl.waitTime = (Tb.EndTime - vipPl.arrvTime);
            Tb.EndTime += vipPl.playTime;
            VipIsIn[VIPS.front()] = true;
            vipPl.num = numb; 
            i--;
            VIPS.pop();
        } else {
    
    
            if(Pl.arrvTime < Tb.EndTime) {
    
    
                Pl.waitTime = (Tb.EndTime - Pl.arrvTime);
                Tb.EndTime += Pl.playTime;
            } else {
    
    
                Tb.EndTime = Pl.arrvTime + Pl.playTime;
            }
            if(Pl.isVipPly){
    
     
                VipIsIn[i] = true;
                VIPS.pop();
            }
            Pl.num = numb;
        }
        numb++;
        Tb.serveNum++;
    }
    sort(player, player+N, [](Player a, Player b){
    
    return a.num < b.num;});
    for(Player &Pl : player) {
    
    
        if(Pl.num == 0xffffff) continue;
        int ah = Pl.arrvTime/3600, am = Pl.arrvTime%3600/60, as = Pl.arrvTime%60, bh = (Pl.arrvTime+Pl.waitTime)/3600, bm = (Pl.arrvTime+Pl.waitTime)%3600/60, bs = (Pl.arrvTime+Pl.waitTime)%60;
        Pl.waitTime = Pl.waitTime/60 + (Pl.waitTime%60 >= 30);
        printf("%02d:%02d:%02d %02d:%02d:%02d %d\n",ah,am,as,bh,bm,bs,Pl.waitTime);
    }
    for(int i = 1;i <= K;++i) cout << table[i].serveNum << (i == K?"\n":" ");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/MYMarcoreus/article/details/115104390