您的位置:首页 > 大数据 > 人工智能

**甲级PAT1014 Waiting in Line (已经通过全部测试,找到一个奇怪的坑但是不知道为什么,跪求大佬回复)

2018-08-24 17:31 806 查看

1014 Waiting in Line (30)(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 customers 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, customer~1~ is served at window~1~ while customer~2~ is served at window~2~. Customer~3~ will wait in front of window~1~ and customer~4~ will wait in front of window~2~. Customer~5~ will wait behind the yellow line.

At 08:01, customer~1~ is done and customer~5~ enters the line in front of window~1~ since that line seems shorter now. Customer~2~ will leave at 08:02, customer~4~ at 08:06, customer~3~ at 08:07, and finally customer~5~ at 08:10.

Input

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

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

[code]2 2 7 5
1 2 6 4 3 534 2
3 4 5 6 7

Sample Output

[code]08:07
08:06
08:10
17:00
Sorry

题目要求: 

这题就相当于模拟银行在运行时候的样子,有N个窗口,设有黄色警戒线,每个窗口黄色警戒线里最多能有M个人,一共有K个客户,银行从上午8:00开始营业,一共有K个客户(id从1~N)每个客户在选择黄线时会选择最短的线路等待。如果有两条或更多条具有相同长度的线,客户将总是选择最小的窗口。依次对队伍中每个人进行服务,服务完的客户离开下一人继续服务。如果客户在下午17:00之前(不包括17:00)还没有开始服务,则不能进行服务。输出Q个客户查询到自己的结束时间,若能服务,则按格式输出时间,若不能服务,则输出sorry

解题思路:

模拟银行的排队情况可以用队列,因为队列具有先来先服务的性质,和银行排队的要求相同。每一个窗口对应一个队列,记录队列的进出情况。题目要求中的每个客户在选择黄线时会选择最短的线路等待。如果有两条或更多条具有相同长度的线,客户将总是选择最小的窗口。等同于在警戒线外的人需要等待哪个窗口在服务的人最先离开,就去哪个窗口,对于同时有多个窗口有人离开,则选择最小的窗口。所以离开和进入是同时发生的。

我这里选用的思路是若有人进入队列则就知道他结束的时间,所以需要用last[i]保留第i号窗口中队列中最后一个人的id。结束时间是先用分钟计时,从0开始,每个窗口初始第一个被服务的人结束时间直接为他所需服务时间,其他后进入的人的结束时间为队列中最后一个人的结束时间和他本身所需时间之和。而且判断该客户能否服务并不是看他的结束时间是否>540而是看未进入队列时最后一个人的结束时间。当队列中最后一个人的服务时间如果>=540,说明将要进入队列的这个人一定不能服务,用数组exceed[i]为1记录第i个客户不能进行服务,而且同时要更新last数组的值。

首先需要初始化所有队列的情况,因为黄线内在开始服务时就已经站满,进行M次循环,从0号窗口开始到N号窗口,依次按id号增大的顺序。然后如果有客户在黄线外则需要模拟进队出队的操作。如何让等待的用户选择最短的线路等待,这个就要模拟时间的进行。从第0分钟到第540分钟,如果窗口队列中正在服务的第一个到了他的结束时间,就离开队伍,这时下一个id的人就会进入到当前窗口的队伍。同初始化进入队列一样。

注意:

1.对于队列数组不能直接写成queue<int> q[5]会报错,而是要用结构体,将队列放入结构体中

2.这里是17:00之前开始服务,对于之前开始服务但是服务结束时间超过17:00的,不是输出Sorry而是对应结束时间,当然由于这题小时的范围限制8-17,分钟的范围限制在0-59,因此哪怕超时也不会超过18:00的。

3.当客户进入一个窗口的队伍中,哪怕其他窗口都没有人了,他也不会换队

4.输出格式要正确。printf("%02d:%02d\n",h,m); 这样如果不够2位可以在左边补0

5.若540分钟模拟结束,还有客户没有进入队伍,则剩下的客户全部都不能进行服务,更新exceed数组的状态,如果少了这一步,第四个测试样例会报错。

6.(不能理解的坑)按照我这种思路,在对模拟进出队列时的过程中若此时客户的id已经超过了客户最大的id值N,则需要break,否则最后一个样例怎么也通不过。按我的想法来说break是否有应该不影响才对,不break只是会对之后的id进行计算,虽然好像会产生数组越界的情况,c++是允许越界的,但是查询的时候,id还是在范围内,范围内的数据肯定会对的。所以没想明白。

完整代码:

[code]#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
#define maxn 22
#define maxm 12
#define maxk 1002

typedef struct MulQueue{
queue<int> q;
}mulqueue;

mulqueue mulq[maxn]; //每个窗口的队列

int needtime[maxk]; //每个客户需要服务的时间
int endtime[maxk];  //每个客户结束时间
int exceed[maxk]; //每个客户是否超过服务时间,为0表示能服务,为1表示不能服务
int last[maxn]; //每个窗口黄线以内每秒对应的最后一个客户id
int N,M,K,Q; //窗口数,黄线以内最大人数,客户数,需查询客户数
int temp=1; //下一个进入黄线内的客户id

int main(){
int i,j,min,first,id,front,h,m;
cin>>N>>M>>K>>Q;
for(i=1;i<=K;i++){
cin>>needtime[i];
}
memset(last,0,sizeof(last));
memset(endtime,0,sizeof(endtime));
memset(exceed,0,sizeof(exceed));
//初始化队列状态
for(i=0;i<M;i++){
for(j=0;j<N;j++){
front = last[j];
if(endtime[front]>=540){
exceed[temp] = 1;
}
mulq[j].q.push(temp);
endtime[temp] = endtime[front]+needtime[temp];
last[j] = temp;
temp++;

}
}
//若黄线外有人等待
if(temp<=K){
for(i=0;i<=540;i++){
for(j=0;j<N;j++){
if(!mulq[j].q.empty()){
first =	mulq[j].q.front();
if(endtime[first] == i){
mulq[j].q.pop();
front = last[j];
if(endtime[front]>=540){
exceed[temp] = 1;
}
mulq[j].q.push(temp);
endtime[temp] = endtime[front]+needtime[temp];
last[j] = temp;
temp++;
if(temp>K) break; //这个if(temp>K) break;和下面那个只要有一个最后一个测试点都不报错,两个同时没有就报错
}
}
}
if(temp>K) break;
}
}

for(i=temp;i<K+1;i++){
exceed[i] = 1;
}

for(i=0;i<Q;i++){
cin>>id;
if(exceed[id] == 1){
cout<<"Sorry"<<endl;
}else{
h = 8 + endtime[id] /60;
m = 0+ endtime[id] %60;
printf("%02d:%02d\n",h,m);
}
}
return 0;
}

忍不住想吐槽一下,这题的最后一个坑找了我好几个小时,测试点怎么都没问题,能想关于测试点的坑都想遍了,还是最后试出来的这个坑。如果以后我弄明白了再来填坑。

 

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐