PAT1014 Waiting in Line 《论正确理解题意的重要性》

1014. Waiting in Line (30)

Suppose a bank has N windows open for service. There is a yellow line in front of the windows which devides the waiting area into two parts. The rules for the customers to wait in line are:

  • The space inside the yellow line in front of each window is enough to contain a line with M customers. Hence when all the N lines are full, all the customers after (and including) the (NM+1)st one will have to wait in a line behind the yellow line.
  • Each customer will choose the shortest line to wait in when crossing the yellow line. If there are two or more lines with the same length, the customer will always choose the window with the smallest number.
  • Customer[i] will take T[i] minutes to have his/her transaction processed.
    The first N customers are assumed to be served at 8:00am.

Now given the processing time of each customer, you are supposed to tell the exact time at which a customer has his/her business done.

For example, suppose that a bank has 2 windows and each window may have 2 custmers waiting inside the yellow line. There are 5 customers waiting with transactions taking 1, 2, 6, 4 and 3 minutes, respectively. At 08:00 in the morning, customer1 is served at window1 while customer2 is served at window2. Customer3 will wait in front of window1 and customer4 will wait in front of window2. Customer5 will wait behind the yellow line.

At 08:01, customer1 is done and customer5 enters the line in front of window1 since that line seems shorter now. Customer2 will leave at 08:02, customer4 at 08:06, customer3 at 08:07, and finally customer5 at 08:10.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 4 positive integers: N (<=20, number of windows), M (<=10, the maximum capacity of each line inside the yellow line), K (<=1000, number of customers), and Q (<=1000, number of customer queries).

The next line contains K positive integers, which are the processing time of the K customers.

The last line contains Q positive integers, which represent the customers who are asking about the time they can have their transactions done. The customers are numbered from 1 to K.

Output Specification:

For each of the Q customers, print in one line the time at which his/her transaction is finished, in the format HH:MM where HH is in [08, 17] and MM is in [00, 59].Note that since the bank is closed everyday after 17:00, for those customers who cannot be served before 17:00, you must output “Sorry” instead.

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

  改了不知道多少次了,2、4、5就是不能通过。去牛客直接说我通过率0,然后正确的输出值又显示不出来(1000个客人,无法全部显示),但是测试用例应该是没问题的。我只能找了一份AC的代码然后运行之后和我自己输出的放在excel里面对比了一下,发现只有一个区别:别人的代码能输出17点之后的时间(比如17:05),而我的代码会把所有交易结束时间大于17点的统统判定为17点,我真是个自作聪明的小天才!大家再品一品题干这段原文:

Note that since the bank is closed everyday after 17:00

  也就是说!关门时间到了依然要完成当前的服务!那么为什么我会认为关门了就赶人走呢,因为我小时候有过这种经历啊!而且给的例子也是刚好17点下班鬼知道下班了还敢不干活啊!?而且我真的真的很久没去银行办理业务了,难道都是会推迟下班的吗!?我真的都不好意思说我在这题上面花了多少时间,还是贴一下我AC的代码吧。

  总体思路是用k个队列qfront表示黄线前的人,一个队列qbehind表示黄线后的人(队列中存储的是人的编号1-k,而不是他们交易所需时间,这是因为晴神的书里说了:队列最好存储编号而不是结构体之类的东西。至于每个人交易所需时间和编号的对应可关系以用map也可以用结构体,我选择的是map)。时间统一按照分钟数记录,最后输出的时候再转换。

每次循环做几件事情:

1. 找出窗口前剩余时间最小值MIN(也就是qfront.front()最小值)
2. 然后对每个窗口队首元素对应的服务时间减去MIN,如果被减到0了就意味着交易完成,对应qfront出队,qbehind里面的人补充进去(这样也符合题目说的长短相同则优先选择编号最小的队列,至于题目说的最短队列其实也就是m-1,毕竟再短就意味着黄线后面没人了)。
3. 还有一点就是在减MIN之前加一个判断:如果队首的人服务结束时间已经大于等于17点,那么该队列阻塞,之后的各种遍历它都不参与了(很真实,后面的人硬生生堵了一天)。至于那些被堵住的人他们的结束时间会是默认的-1,在转换时间的时候会变成“Sorry”。

代码如下:

#include <iostream>
#include <queue>
#include <map>
using namespace std;
const int maxn = 1010;
int m,n,k,q;
queue<int> qfront[21],qbehind;
string getTime(int);
map<int,int> table;
int curTime=0;//当前时间,随着每轮经历MIN时间而变化
bool flag[21];
int main(){
    scanf("%d%d%d%d", &n, &m, &k, &q);
    vector<int> times(k+1,-1);
    for(int i=1;i<=k;i++){
        int t;
        scanf("%d",&t);
        qbehind.push(i);//先把人全塞进黄线后面
        table[i]=t;
    }
    //初始化黄线前的队列
    for(int i=1;i<=n*m;i++){
        int v = i%n==0? n:i%n;
        if(!qbehind.empty()){
            qfront[v].push(qbehind.front());
            qbehind.pop();
        }
    }
    while(1){
        int MIN=0x3fffffff,u=-1;
        //找出最短的时间MIN
        for(int i=1;i<=n;i++){
            if(!qfront[i].empty() && !flag[i]){
                int v = qfront[i].front(); 
                if(table[v]<MIN){
                    MIN=table[v];
                    u=v;
                }
            }
        }
        if(u==-1) break;//所有窗口都被阻塞或完成
        //所有未被阻塞窗口经历时间MIN
        for(int i=1;i<=n;i++){
            if(!qfront[i].empty() && !flag[i]){
                int t=qfront[i].front();
                //无法在规定时间前完成服务的人会阻塞一个窗口
                if(curTime+table[t]>539){
                    flag[i]=true;
                    times[t]=curTime+table[t];
                    continue;
                }
                table[t]-=MIN;
                //MIN时间过后完成服务的人出队,黄线后的人补充队列
                if(table[t]==0){
                    qfront[i].pop();
                    times[t]=curTime+MIN;
                    if(!qbehind.empty()){
                        qfront[i].push(qbehind.front());
                        qbehind.pop();
                    }
                }
            }
        }
        curTime+=MIN;
    }
    for(int i=0;i<q;i++){
        int t;
        scanf("%d",&t);
        cout<<getTime(times[t])<<endl;
    }
    return 0;
}
string getTime(int t){
    if(t==-1) return "Sorry";
    int h=t/60+8;
    int m=t%60;
    string hh=h>9?to_string(h):"0"+to_string(h);
    string mm=m>9?to_string(m):"0"+to_string(m);
    string ans = hh+":"+mm;
    return ans;
}

总结:

  • 认真审题,宁可多花五分钟在理解题意上面,也不要想当然动手然后填坑花上几倍甚至更多的时间。
  • 根据我的经验,这个考试给的例子很多时候并不能完全解释题目逻辑,需要你有点灵(运)性(气),别想着第一次的理解就一定是对的,有时候需要尝试几种逻辑说不定有一个就AC了。如果代码写的逻辑清晰,其实不同想法的实现并不用改太多东西。
  • 冷静一点,这题花这么多时间说实在的是钻了牛角尖了。一开始觉得简单键盘敲得飞快,伤脑筋起来也是往程序逻辑方面去找错,而没有想过题目理解出了问题,有亿点上头
发布了4 篇原创文章 · 获赞 0 · 访问量 46

猜你喜欢

转载自blog.csdn.net/qq_38399914/article/details/104929576