1014 Waiting in Line (30分)

 

 这题好难的。。想了很久怎么处理,参考了别人的代码,发现一个测试点的疏漏,pat的测试点给的还不是很全面。自己原来的代码就不提了,很垃圾,只过了测试点1拿了12分,还有两个测试点超时,其他测试点答案错误...我还想了好久...太菜了。学习别人的思路,自己改动了一些地方。

1.构造结构体Que,成员有lastend和q,lastend记录每一队的最后一个人的结束时间,q是队列,记录队列每个人的服务时间。lastend的巧妙之处在于,可以通过他判断有人新入队时是否已经超过了17:00。很多人多设置了一个poptime记录队首结束服务的时间,其实没有必要,直接访问队首即可(在队首出队时要对新的队首的服务时间进行更新)

2.pat给的测试点,可能可以概括为一种情况,一定是第一队的队首率先结束服务,我在csdn上找了一份代码,不能正确处理其他队的队首率先服务完毕的情况(这关系到新入队的人应该去哪里排队,直接影响到新入队的人的结束服务时间),然而没考虑到这种情况的代码也能拿满分,说明pat的测试点给的不够全面。

3.如何让在黄线外的人正确入队?策略是,比较每个窗口的队首的结束服务时间,最小的应该先出队,让黄线外的人入这一队,每次仅仅一人出队,也仅仅只有一人入队,即使有人结束服务时间相同,也可以正确处理这个先后顺序。进入黄线内(已经正确入队)的人,结束服务时间就已经确定了。我之前想设置一个共同的时钟,每一队都参照这个时钟出队入队,太麻烦,并且要考虑太多特殊情况,不应该采取这种思路。每个队伍中的人结束服务的时间,仅仅取决于队伍前面的人的服务时间,不要考虑其他队的情况。

4.17:00前还没开始服务的人标记为sorry,17:00前开始服务的人,不管服务时间有多长,都得输出结束服务的时间。

 

 1 #include<iostream>
 2 #include<vector>
 3 #include<cstdio>
 4 #include<queue>
 5 #define inf 0x3f3f3f3f
 6 using namespace std;
 7 struct Que{
 8     int lastend;
 9     queue<int> q;
10     Que(int l=0):lastend(l){}
11 };    
12 int main(){ 
13     int N,M,K,Q,cnt=1;
14     scanf("%d%d%d%d",&N,&M,&K,&Q);
15 //  Que window[N+1];
16 //    int sorry[K+1]={0},据说这样申请数组不好,得用以下方式? 
17     vector<Que> window(N+1);//N个窗口
18     vector<int> sorry(K+1,0); //K个标志,记录是否输出sorry
19     vector<int> time(K+1,0);
20     vector<int> res(K+1);
21     for(int i=1;i<=K;i++)
22     {
23         scanf("%d",&time[i]);
24     }
25     for(int i=1;i<=M;i++)//一行行处理 
26     { for(int j=1;j<=N;j++)
27      { 
28        if(cnt<=K)
29          {if(window[j].lastend>=540)//如果插入前,队伍的最后结束时间超过17:00,则后面插入的应输出sorry 
30             sorry[cnt]=1;
31           window[j].q.push(time[cnt]);
32           window[j].lastend=window[j].lastend+time[cnt];//更新队伍的最后结束时间 
33           res[cnt]=window[j].lastend;
34              cnt++;    
35         }  
36       }    
37      } 
38     int temp;
39     while(cnt<=K){
40         int minwindow=1;//假设第一个窗口最先结束队首业务
41         int min=window[1].q.front();//这里有个小问题注意 
42         for(int i=2;i<=N;i++){             //别人的处理使得第一个窗口的第一个人始终最先被服务完 
43            if(window[i].q.front()<min){
44                  minwindow=i;
45                  min=window[i].q.front();
46            } 
47         } 
48         temp=window[minwindow].q.front();//队首出队前保存这个值 
49         window[minwindow].q.pop();// 队首出队 
50         if(window[minwindow].lastend>=540)//如果入队前,队伍的最后结束时间超过17:00,则后面插入的应输出sorry 
51             sorry[cnt]=1;
52         window[minwindow].q.push(time[cnt]);
53         window[minwindow].lastend= window[minwindow].lastend+time[cnt];
54         res[cnt]=window[minwindow].lastend;
55         window[minwindow].q.front()=temp+window[minwindow].q.front();//入队后才更新队首结束时间
56         cnt++; 
57     }
58     int num,HH,MM;
59     for(int i=0;i<Q;i++)
60     {    scanf("%d",&num);
61         if(sorry[num])
62           printf("%s\n","Sorry");
63         else
64         {
65         HH=(res[num]+480)/60;MM=(res[num]+480)%60;
66         printf("%02d:%02d\n",HH,MM);    
67         }
68      } 
69     return 0;
70 }

 自己写的代码,12分,没有学习的价值...自己再写一遍都可能复现不了这样的思路...如下:

 1 #include<iostream>
 2 #include<vector>
 3 #include<cstdio>
 4 #include<queue>
 5 using namespace std;
 6 queue<int> Que[21];
 7 queue<int> waiting;
 8 int N,M,size;
 9 int serve(int start,int T){
10     if(start>=1020||start<0)
11       return -1;
12     else
13       return start+T;
14 }
15 void pick(){
16     int min=Que[0].size();
17     int k=0;
18     for(int i=0;i<N;i++)
19         if(min>Que[i].size())
20              {    min=Que[i].size();
21                  k=i;
22              }
23     for(int i=0;i<N;i++)
24      if(min==Que[i].size()&&!waiting.empty())
25        {Que[i].push(waiting.front());
26         size++;
27            waiting.pop();     
28        }        
29 }    
30 int main(){ 
31    int K,Q,time;
32    scanf("%d%d%d%d",&N,&M,&K,&Q);
33    if(K>=N*M)
34       size=N*M;
35     else
36       size=K;
37    int cus_time[2020]={0};
38    for(int i=1;i<=K;i++)
39    {scanf("%d",&time);
40        cus_time[i]=time;
41    } 
42    for(int i=1,j=0;i<=N*M;i++)
43         Que[(j++)%N].push(i);    
44    for(int i=N*M+1;i<=K;i++)
45      waiting.push(i);
46      
47     int res[2020]={0}; 
48     int now=480;
49     int min;
50     int m; 
51     while(size!=0){//当还有人在排队时,继续 
52         for(int i=0;i<N;i++)//假设第一个非空队伍的队首为最早结束 
53         {if(!Que[i].empty())
54          {min=serve(now,cus_time[Que[i].front()]);
55           m=cus_time[Que[i].front()];
56           break;    
57          }
58         }
59         for(int i=0;i<N;i++){//这个循环作用是,找到所有队首的结束时间(这个时间记为min)最早的队伍(可能不止一队) 
60           if(!(Que[i].empty())&&(min>serve(now,cus_time[Que[i].front()])))
61            {
62            min=serve(now,cus_time[Que[i].front()]);
63            m=cus_time[Que[i].front()];
64            }
65         }
66         for(int i=0;i<N;i++)//这个循环的作用是,最早结束的队首出队(可能不止一队),同时更改当前时间 
67         {
68             if( !(Que[i].empty())  )
69               if(min==serve(now,cus_time[Que[i].front()])  )
70               { now=serve(now,cus_time[Que[i].front()]);
71                   res[Que[i].front()]=now;
72                 Que[i].pop();
73                 size--; 
74               }//如果不是最早出队的,需要更新业务处理时间 
75                else
76                 cus_time[Que[i].front()]=cus_time[Que[i].front()]-m;       
77         }
78         pick();//当有人出队(不管是一人还是几人),仅仅令等待队伍中的一人进队
79 }
80     int num,HH,MM;
81     for(int i=0;i<Q;i++)
82     {    scanf("%d",&num);
83         if(res[num]<0)
84           printf("%s\n","Sorry");
85         else
86         {
87         HH=res[num]/60;MM=res[num]%60;
88         printf("%02d:%02d\n",HH,MM);    
89         }
90      } 
91     return 0;
92 }
View Code

有缺陷的代码,不能正确处理上面第2点的情况,但仍可以拿满分:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <queue>
 4 #include <vector>
 5 using namespace std;
 6 struct node{
 7     int poptime, endtime;//队首的人出队(结束)时间  队尾的人结束时间
 8     queue<int> q;
 9 };
10 int main()
11 {
12     //n个窗口(n<=20) m为黄线内最大容量(m<=10) k个顾客(k<=1000) q为要查询的顾客人数(q<=1000)
13     int n, m, k, p, index=1;
14     scanf("%d%d%d%d", &n, &m, &k, &p);
15     vector<int> time(k+1), result(k+1);//顾客办理业务所需时间  顾客办理业务结束时间
16     for(int i=1; i<=k; i++)
17         scanf("%d", &time[i]);
18     vector<node> window(n+1);//n个窗口n个队
19     vector<bool> sorry(k+1, false);
20     //处理开始就在黄线内顾客 前面m*n
21     for(int i=1; i<=m; i++){
22         for(int j=1; j<=n; j++){
23             if(index <= k){
24                 window[j].q.push(time[index]);
25                 if(window[j].endtime >= 540)//队尾的人结束时间超过下午五点
26                     sorry[index] = true;
27                 window[j].endtime += time[index];
28                 result[index] = window[j].endtime;
29                 index++;
30             }
31         }
32     }
33     //开始无法排进黄线内  m*n以后的人
34     while(index <= k){
35         int minPoptime=window[1].poptime, minWindow=1;
36         for(int i=2; i<=n; i++){//寻找最先有人出来的窗口
37             if(window[i].poptime < minPoptime){
38                 minPoptime = window[i].poptime;
39                 minWindow = i;
40             }
41         }
42         window[minWindow].q.pop();//出队一个
43         window[minWindow].q.push(time[index]);//入队
44         window[minWindow].poptime += window[minWindow].q.front();//更新队首结束时间
45         if(window[minWindow].endtime >= 540)
46             sorry[index] = true;
47         window[minWindow].endtime += time[index];//更新队尾结束时间
48         result[index] = window[minWindow].endtime;//记录该顾客结束时间
49         index++;
50     }
51     for(int i=1; i<=p; i++){
52         int check;
53         scanf("%d", &check);
54         int temp = result[check];
55         if(sorry[check] == true)
56             printf("Sorry\n");
57         else
58             printf("%02d:%02d\n", (temp+480)/60, (temp+480)%60);//480 早上八点
59     }
60     return 0;
61 }
View Code

来源:https://blog.csdn.net/whl_program/article/details/77687337

 

posted @ 2020-03-15 15:11  wsshub  阅读(281)  评论(0)    收藏  举报