【PAT甲级 模拟、优先队列、模拟时间】1017 Queueing at Bank (25 分)

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

int N ,K;
int EndTime[100]; // 上一个客户结束服务的时间
struct Customer{
    int arriveTime;  // 客户到达时间
    int processTime; // 客户办理业务的时间
}cust[10000];

struct cmp{
    bool operator()(const int &a, const int &b) { // 优先队列的重载小于号是常引用并且是const函数
        return cust[a].arriveTime > cust[b].arriveTime;
    }
};
priority_queue<int, vector<int>, cmp> Q; // 等待队列,存放编号(根据到达时间来排序编号)


int main() {
    double ans = 0.0;
    int realN = 0;
    cin >> N >> K;
    for(int i = 0;i < N;++i) {
        int hour, minute, second, p;
        scanf("%d:%d:%d %d\n", &hour, &minute, &second, &p);
        if(p > 60) p = 60;
        cust[i].arriveTime = (hour*60 + minute) * 60 + second;
        cust[i].processTime = p*60;
        if(cust[i].arriveTime <= 61200){
            Q.push(i);
            realN++;
        }
    }
    for(int i = 0;i < K;++i)
        EndTime[i] = 28800;
    
    while(!Q.empty()){
        // 寻找最早结束时间的窗口
        int popWindow = 0;
        for(int windowID = 1;windowID < K;++windowID) 
            if(EndTime[windowID] < EndTime[popWindow])
                popWindow = windowID;

        Customer &nowCust = cust[Q.top()];
        if(nowCust.arriveTime < EndTime[popWindow]) { // 来早了需要等待
            ans += (EndTime[popWindow] - nowCust.arriveTime);
            EndTime[popWindow] += nowCust.processTime;
        } else { // 来晚了可以直接开始
            EndTime[popWindow] = nowCust.arriveTime + nowCust.processTime;
        }

        Q.pop();
    }
    printf("%.1lf\n", ans/(60.0*realN));

    return 0;
}

折磨了一天,终于用模拟时间的方法做出来了!!!!很开心

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

int N ,K;
struct Cust{
    int arriveTime;
    int processTime;
}cust[10000];

struct cmp{
    bool operator()(const int &a, const int &b) { // 优先队列的重载小于号是常引用并且是const函数
        return cust[a].arriveTime > cust[b].arriveTime;
    }
};
priority_queue<int, vector<int>, cmp> Q; // 等待队列,存放编号

int EndTime[100];   // 第i个窗口上一次的客户离开窗口的时间
int EnterTime[100]; // 第i个窗口这一次的客户进入窗口的时间
queue<int> window[100]; // 模拟窗口,队列最多只有一个人
double ans = 0.0; // 记录总等待时间
int realN = 0; // 有效的客户个数

void get_ans() {
	/*模拟时间, 每一秒都根据窗口是否有人来处理
	对于每一秒的所有窗口:
		如果窗口有人:
			那就等到这个人结束业务的时间让他离开,更新离开时间
		如果窗口没人:
			那就在黄线外让最早到达的人进入窗口,更新进入时间
				如果最早到达的人到达的时候没有窗口结束业务,那就等到第一个窗口业务结束,然后进入
				如果最早到达的人到达的时候有空闲窗口,那就直接进入,无需等待
	*/
    for(int second = 28800;second <= 61200 || !Q.empty();++second) {//Q中都是有效的客户
        for(int winID = 0;winID < K;++winID) { // 检查窗口
            queue<int> &win = window[winID];
            if(!win.empty()) { // 窗口有人在办理业务
            	// 如果到了业务办理结束的时间就让这个人离开窗口,并记录用户离开窗口的时间
                if(second == (EnterTime[winID] + cust[win.front()].processTime)) {
                    win.pop();
                    EndTime[winID] = second;
                }
            }
            //这个if必须放在上面一个if下面,因为在上一个if pop之后这里的if负责让客户进入
            if(win.empty() && !Q.empty()) { // 窗口空且有人
            	// 如果到了当前窗口业务结束的时间
                if(second == EndTime[winID]){
                    int custID = Q.top(); // 这个人将要进入窗口,所以记录他来更新进入时间和总等待时间
                    
                    if(cust[custID].arriveTime < EndTime[winID]) { // 来早了窗口业务还没结束,等到业务结束
                        ans += (second - cust[custID].arriveTime);
                        EnterTime[winID] = EndTime[winID]; // 等到业务结束才进去
                    } else {
                        EnterTime[winID] = cust[custID].arriveTime; // 如果到达时,窗口是空闲的,就可以直接进去,不需要等待
                    }
                    
                    win.push(custID); // 进入窗口
                    Q.pop(); // 黄线外的等待队列少一人
                }
            }
        } // end_innner for
    } // end_outter for
}


int main() {
    cin >> N >> K;
    for(int i = 0;i < N;++i) {
        int hour, minute, second, p;
        scanf("%d:%d:%d %d\n", &hour, &minute, &second, &p);
        if(p > 60) p = 60;
        cust[i].arriveTime = (hour*60 + minute) * 60 + second;
        cust[i].processTime = p*60;
        if(cust[i].arriveTime <= 61200){
            Q.push(i);
            realN++;
        }
    }
    fill(EndTime, EndTime+K, 28800);
    fill(EnterTime, EnterTime+K, 28800);
    get_ans();

    printf("%.1lf\n", ans/(60.0*realN)); // 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值