PAT_甲级_1014 Waiting in Line (30分) (C++)

目录

1,题目描述

题目大意

输入

输出

2,思路

存储结构

 处理过程

注意

队列(头文件:queue)的常用函数:

3,代码


1,题目描述

Sample Input:

2 2 7 5
1 2 6 4 3 534 2
3 4 5 6 7

Sample Output:

08:07
08:06
08:10
17:00
Sorry

题目大意

银行里有N个窗口,每个窗口前有一条黄线,黄线内可容纳M个人,每个黄线之后的人在穿越黄线时,会选择当前排队人数最少的一个窗口,(而且一旦进入黄线内,不再切换窗口),若两个以上的窗口等待人数相等且最短,则选择编号最小的窗口。

输出前来询问的顾客的交易结束时间;

输入

第一行:N:窗口数(<=20),M:黄线内容量(<=10),K:顾客数量(<=1000,编号1-K),Q:询问交易结束时间的顾客数量(<=1000);

第二行:各顾客的交易处理时间;

第三行:询问交易结束时间的顾客编号

输出

给出每位询问顾客的交易结束时间(以HH:MM的形式给出,HH取值[08,17],MM取值[00,59],若交易结束时间晚于17:00,输出Sorry)

2,思路

模拟题(过程及细节较为繁琐,容易出错,但思路简单),队列的应用

存储结构

  • n:窗口数,m:黄线容纳数,k:顾客数,q:询问的顾客数;
  • queue<int> window[20]:窗口队列,窗口数目不超过20,编号从0开始;
  • int customer[1001][2]:存放顾客的[0]处理需求时间,[1]服务结束时间;
  • int back[1001]:存放顾客的处理需求时间(备份)

 处理过程

  1. 输入顾客相关的数据,并备份;
  2. 填满黄线内的所有窗口。num = n * m < k ? n * m : k;
  3. 若黄线外有顾客,则按照出一个人,进一个人的方法模拟(每出一个人,更新正在处理需求的所有人的处理时间,以及从营业开始到现在的总用时time【用分钟来表示】);
  4. 若黄线外无顾客,则每个窗口计算一次,可直接得出正在排队的所有人的业务处理结束时间;
  5. 输出时,若顾客的服务开始时间早于17:00,但结束时间晚于17:00,仍属于服务区间不输出Sorry,即customer[c][1] - back[c] < 540;

注意

  1. 顾客1->窗口0, 顾客2->窗口1, ...... 顾客m->窗口0 ,顾客m+1->窗口1 ;
  2. 顾客的编码从1开始;
  3. printf("%02d:%02d\n", h, m)输出时钟规格(HH:MM:SS)的数据很方便;

队列(头文件:queue)的常用函数:

入队:q.push(x); 将x接到队列的末端。

出队:q.pop(); 弹出队列的第一个元素,注意,并不会返回被弹出元素的值。

访问队首元素:q.front(),即最早被压入队列的元素。

访问队尾元素:q.back(),即最后被压入队列的元素。

判断队列空:q.empty(),当队列空时,返回true。

访问队列中的元素个数:q.size()

 

3,代码

#include<iostream>
#include<queue>
#include<climits>
using namespace std;

int main(){
    int n, m, k, q;                     //n:窗口数,m:黄线容纳数,k:顾客数,q:询问的顾客数
    int time = 0;                       //当前时间已过08:00多少分钟
    int index;                          
    scanf("%d%d%d%d", &n, &m, &k, &q);

    queue<int> window[20];              //最多有20个窗口
    int customer[1001][2];              //最多有1000名顾客(编号从1开始) 存放顾客需求的[0]处理时间和[1]结束时间
    int back[1001];                     //对游客的问题处理时间进行备份
    for(int i = 1; i <= k; i++){        //游客编号从1开始!!!
        scanf("%d", &customer[i][0]);
        back[i] = customer[i][0];
    }

    int num = n * m < k ? n * m : k;    //先按规则 依次填满黄线内的窗口
    index = 1;
    while(index <= num){
        for(int j = 0; j < n; j++){     //顾客1->窗口0 顾客2->窗口1 ...... 顾客m->窗口0 顾客m+1->窗口1
            window[j].push(index);
            index++;
        }
    }

    //当黄线之外还有顾客时 一直会有进有出
    index = n * m + 1;                  //当前黄线外第一位顾客的序号
    while(index <= k){
        int fastWin = 0;                //记录窗口中最快结束的那个窗口
        int minTime = INT_MAX;          //记录当前各个窗口正在处理的客户中 剩余最短时间
        for(int i = 0; i < n; i++){
            if(customer[window[i].front()][0] < minTime){
                minTime = customer[window[i].front()][0];
                fastWin = i;
            }
        }
        for(int i = 0; i < n; i++){     //更新正在窗口前处理问题的客户的剩余时间
            customer[window[i].front()][0] -= minTime;  
        }
        time += minTime;                //总计时累加
        customer[window[fastWin].front()][1] = time;
        window[fastWin].pop();
        window[fastWin].push(index++);

    }

    //黄线之外无客户 只出不进 可直接计算出各个客户的结束服务时间
    for(int i = 0; i < n; i++){         //按顺序依 次计算每个窗口队列中各客户的服务结束时间
        int temp = time;
        while(window[i].empty() != true){
            int x = window[i].front();
            window[i].pop();
            time += customer[x][0];
            customer[x][1] = time;
        }
        time = temp;                    //由于是每个队列计算一次 故需要恢复原始的time
    }

    for(int i = 0; i < q; i++){
        int c;
        scanf("%d", &c);
        if(customer[c][1] - back[c] < 540){ //由于原始数据在计算过程中丢失 故需使用备份back
            int h = 8 + customer[c][1] / 60;
            int m = customer[c][1] % 60;
            printf("%02d:%02d\n", h, m);    //学到了!!!
        }
        else{
            printf("Sorry\n");
        }
    }
    return 0;
}
发布了45 篇原创文章 · 获赞 5 · 访问量 2187

猜你喜欢

转载自blog.csdn.net/qq_41528502/article/details/104232311
今日推荐