PAT甲级1014

PAT甲级1014 队列模拟题

解题思路:

很明显这是一个模拟题,个人觉得很经典。首先,利用nowTime的递增来模拟时间的增长,真正的难点在于寻找一个合适模拟方式,使得题目要求入队方式完美实现,并且还可以精准的计算时间。在这里,用N个队列模拟服务区,用一个wait模拟等待区,只要服务区一有空闲,等待区的人立刻补充上。因为服务区是从1~N进行循环检查的,所以完全可以满足题目中要求从低的开始补齐,而且服务区出队的时候,立刻有等待的人补充上。对于时间的控制来说,不是使用DP,刚开始还想用DP来解决,后来发现思路是错的;应该是利用时间模拟的过程中,动态地进行局部的时间计算,即每次只计算队头的时间,这样,在模拟结束的时候,就可以获取所有的时间结果了。
其他的一些注意事项在代码的注释中写出了。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 21;
const int MAXK = 1005;
int N, M, K, Q;
struct Person {
    int id, serverTime;      // 编号 服务时长
    int BeginTime, EndTime;  // 开始结束时间
    Person(): BeginTime(0), EndTime(-1), serverTime(0), id(0) {} // EndTime为-1说明sorry
} Per[MAXK];
queue<Person>line[MAXN], wait;
int main() {
    cin >> N >> M >> K >> Q;
    int cap = N * M;
    for(int i = 1; i <= K; ++i) {  // 输入时间部分
        cin >> Per[i].serverTime;
        Per[i].id = i;
        if(i <= N) {
            Per[i].EndTime = Per[i].serverTime; // 每个窗口第一个排上队的肯定能服务完
        }
        if(i <= N * M) { // 人先把缓冲服务区加满
            line[(i - 1) % N + 1].push(Per[i]); // 注意这种取整运算的技巧
        } else {         // 等待队列
            wait.push(Per[i]);
        }
    }
    int countC = K;
    int nowTime = 0, closeTime = 9 * 60;
    while(nowTime < closeTime && countC) { // 时间没结束,而且有人在服务
        nowTime++;
        for(int i = 1; i <= N; ++i) {
            if(line[i].empty()) {  // 处理出现空窗口的情况
                continue;
            }
            Person head = line[i].front();
            // 注意第二个判断条件,为了控制测试数据中最后的那个例子类型的
            if(head.EndTime <= nowTime || head.EndTime > closeTime) {  
                line[i].pop();
                countC--;
                // 下面两行完成时间更替
                line[i].front().BeginTime = head.EndTime;
                line[i].front().EndTime = head.EndTime + line[i].front().serverTime;
                // 完成数据存储
                Per[head.id].BeginTime = head.BeginTime;
                Per[head.id].EndTime = head.EndTime;
                if(!wait.empty()) { // 如果还有人等待,就立即加入进来
                    line[i].push(wait.front());
                    wait.pop();
                }
            }
        }
    }
    int q;
    for(int i = 1; i <= Q; ++i) {
        cin >> q;
        if(Per[q].EndTime == -1) {
            cout << "Sorry" << endl;
        } else { // printf输出的技巧
            printf("%02d:%02d\n", Per[q].EndTime / 60 + 8, Per[q].EndTime % 60);
        }
    }
    return 0;
}
/*
测试案例,注意最后那个例子,结束时间超出17:00没事
输入:
2 2 9 9
1 2 6 4 3 1 9 100 534
1 2 3 4 5 6 7 8 9
输出:
08:01
08:02
08:07
08:06
08:10
08:07
08:16
09:50
17:10
*/
一些小感想:

个人感觉,题目真的很好,学会了一种新方式。虽然刚开始接触这题时,花了灰常长的时间,,,在参考了dalao的blog后,实现了。。每日都要有进步啊

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值