【PAT 甲级 模拟】1014 Waiting in Line (30 分)

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

/*
N个窗口,黄线内才会有队伍(N条队伍),每条队伍最多有M个人;
当黄线内的人没满(人数共小于NM个人),就可以直接得出答案了
当黄线内的人满了(大于等于NM个人), 那么黄线外的人就需要等待窗口的人办完业务,然后等待某条队伍有人办理完业务
	(如果有多条同时办理完业务的人而空出来的队伍,就选择编号较小的队伍)
 
银行营业时间为8~17点
输出每位查询的顾客办理完业务的时间
根据编号大小决定顺序
黄线内每个人在队伍的顺序是类似于二维数组遍历的顺序
黄线外的人编号大的人先进入队伍
*/
int N, M, K, Q; // 窗口数、黄线内单条队伍的最大长度、总顾客数、要查询的顾客数
int eachTime[1010];          // 每位客户所需的服务时间
int ans[1010];               // 存放每位客户的服务结束时间
map<int, int> windowPopTime; // 队首客户的服务结束时间
int windowEndTime[21];       // 窗口的服务结束时间(在黄线外时,是入队的客户的服务结束时间)
vector< queue<int> > Que;    // 模拟窗口队列

int main() {
    cin >> N >> M >> K >> Q;
    Que.resize(N+1);
    for(int i = 1;i <= K;++i) // 输入所有K个顾客的办理业务所需时间(每个顾客编号从1-K)
        scanf("%d", &eachTime[i]);

    for(int i = 1;i <= N*M && i <= K;i+=N) { // 这里都是在黄线内的
        for(int window = 1, custid = i;window <= N && custid <= K;++window, custid++) {
            Que[window].push(custid);

            windowEndTime[window] += eachTime[custid]; // 累加得到当前队伍的服务结束时间
            if(custid <= N) // 窗口第一个用户
                windowPopTime[Que[window].front()] = eachTime[Que[window].front()];
            ans[custid] = windowEndTime[window]; // 黄线内的队伍已经排定了,直接得出答案
        }
    }

    for(int nowCust = N*M+1;nowCust <= K;++nowCust) { // 处理在黄线外的顾客
    	// 用map的话可以保存编号就可以写一个比较函数,就能解决服务结束时间相等的问题了
        pair<int, int> p = *min_element(windowPopTime.begin(), windowPopTime.end(), [](pair<int, int> a, pair<int, int> b){
            if(a.second == b.second)
                return a.first < b.first;
            return a.second < b.second;
        });
        int minWindow = p.first;

		// 当然windowPopTime用vector的话就自己写一个min函数咯
        // int minWindow = -1, minPopTime = 0xffffff;
        // for(int window = 1;window <= N;++window){
        //     if(windowPopTime[window] < minPopTime) {
        //         minWindow = window;
        //         minPopTime = windowPopTime[window];
        //     }
        // }

        Que[minWindow].pop();
        Que[minWindow].push(nowCust);
        windowEndTime[minWindow] += eachTime[nowCust];
        windowPopTime[minWindow] += eachTime[Que[minWindow].front()];
        ans[nowCust] = windowEndTime[minWindow];

    }

    for(int i = 0;i < Q;++i){ // Q次查询
        int queryCus;
        scanf("%d", &queryCus);
        // 服务开始时间在17点之前的都可以完成服务(即使超过了17点)
        if(ans[queryCus] - eachTime[queryCus] < 540){ // 测试点2、4、5坑点,减去eachTime才是服务开始时间
            int hour   = 8 + ans[queryCus] / 60;
            int minute = ans[queryCus] % 60;
            printf("%02d:%02d\n", hour, minute);
        }
        else{
            cout << "Sorry\n";
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值