题目链接:http://www.patest.cn/contests/pat-a-practise/1017
题目:
Suppose a bank has K windows open for service. There is a yellow line in front of the windows which devides the waiting area into two parts. All the customers have to wait in line behind the yellow line, until it is his/her turn to be served and there is a window available. It is assumed that no window can be occupied by a single customer for more than 1 hour.
Now given the arriving time T and the processing time P of each customer, you are supposed to tell the average waiting time of all the customers.
Input Specification:
Each input file contains one test case. For each case, the first line contains 2 numbers: N (<=10000) - the total number of customers, and K (<=100) - the number of windows. Then N lines follow, each contains 2 times: HH:MM:SS - the arriving time, and P - the processing time in minutes of a customer. Here HH is in the range [00, 23], MM and SS are both in [00, 59]. It is assumed that no two customers arrives at the same time.
Notice that the bank opens from 08:00 to 17:00. Anyone arrives early will have to wait in line till 08:00, and anyone comes too late (at or after 17:00:01) will not be served nor counted into the average.
Output Specification:
For each test case, print in one line the average waiting time of all the customers, in minutes and accurate up to 1 decimal place.
Sample Input:7 3 07:55:00 16 17:00:01 2 07:59:59 15 08:01:00 60 08:00:00 30 08:00:02 2 08:03:00 10Sample Output:
8.2
分析:
和1014(http://blog.csdn.net/apie_czx/article/details/45537627)题目很相近的题意,不过有区别就是这里的顾客来的时间是随机的。而且在能否得到服务这一点上也是不同的,1014中是即使你在队伍当中,但是如果你在指定时间内(17:00)之前没有 得到服务,那么也是Sorry,而本题中只要你排进了队伍,那么即使超过了五点,也是顺延计算你的时间。
注意点:
最初我还是用时间作为循环变量来进行,但是这样做就不能计算超过17:00的剩余队伍的人的等待时间(因为你无法计算队伍中的人要多久,所以不能设定一个结束时间)
正确的做法应该是把时间循环结束到五点,然后计算队伍中剩下的人。
案例分析:
7个顾客,3个队伍
对顾客的时间排序,
顾客 | 服务时间 | 开始时间 | 等待时间 |
---|---|---|---|
07:55:00 | 16 | 08:00:00 | 00:05:00 |
07:59:59 | 15 | 08:00:00 | 00:00:01 |
08:00:00 | 30 | 08:00:00 | 00:00:00 |
08:00:02 | 2 | 08:15:00 | 00:14:58 |
08:01:00 | 60 | 08:16:00 | 00:15:00 |
08:03:00 | 10 | 08:17:00 | 00:14:00 |
17:00:01 | 2 | Sorry | 无 |
AC代码:
#include<stdio.h> #include<vector> #include<algorithm> using namespace std; struct Time{ int hour; int minute; int second; };//时间结构体 int turn2sec(Time T){ return T.hour * 60 * 60 + T.minute * 60 + T.second; }//把时间化为秒 struct Customer{ int s_time; int server_time; bool operator < (const Customer &A)const{ return s_time < A.s_time; }//顾客结构体,以及比较函数,按到达的先后 }buf[10002]; int ans[10002];//存储各个顾客的等待时间 int queue[102];//队伍,存储顾客编号 int main(void){ //freopen("F://Temp/input.txt", "r", stdin); int N, K; while (scanf("%d%d", &N, &K) != EOF){ Time tmp; for(int i = 0; i < N; i ++){ scanf("%d:%d:%d", &tmp.hour, &tmp.minute, &tmp.second); buf[i].s_time = turn2sec(tmp); int server; scanf("%d", &server); buf[i].server_time = server * 60; } sort(buf, buf + N); for (int i = 0; i < K; i++){ queue[i] = -1; } for (int i = 0; i < N; i++){ ans[i] = -1; }//初始化 int count = 0; for (int t = 28800; t <= 864000 && buf[count].s_time <= 61200; t++){//为了应对五点前有顾客开始服务,但是结束的时间超过五点,所以这里的t设置的很大 for (int i = 0; i < K; i++){ if (queue[i] != -1){ int tmp = queue[i]; if ((buf[tmp].s_time + ans[tmp] + buf[tmp].server_time) == t){//如果到达时间+等待时间(即开始时间)+服务时间==当前时间,则出对 queue[i] = -1; } } } for (int i = 0; i < K; i++){ if (queue[i] == -1 && t >= buf[count].s_time){ queue[i] = count;//如果队伍有空,并且当前时间大于顾客的到达时间,则入队 ans[count] = t - buf[count].s_time;//并计算等待时间 count++; } } } int sum = 0; int i; for (i = 0; i < N; i++){ if (ans[i] == -1)break; else{ sum += ans[i]; } } if (i == 0)printf("0/n"); else printf("%.1f\n", (double)sum / i / 60); } return 0; }
其实更好的办法的用窗口来,王道的代码如下:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int N,K,wait_time=0; struct Customer { int arrive_time; int need_time; }; struct Customer customer[10002]; struct Windows { int next_available_time; };//特别得,窗口结构体,里面是当前顾客的结束时间,也就是窗口下一次空闲的时间 struct Windows windows[102]; bool cmp(struct Customer a,struct Customer b) { return a.arrive_time<b.arrive_time; } int find_available_windows(int arrive_time) { int i; for(i=0;i<K;i++) { if(windows[i].next_available_time<=arrive_time) { return i; } } return -1; }//找到空闲的窗口 int find_earliest_window() { int i; int e=0; for(i=1;i<K;i++) { if(windows[i].next_available_time<windows[e].next_available_time) { e=i; } } return e; }//找到最早的空闲窗口 int main() { scanf("%d%d",&N,&K); int i; char arrive_time[20]; int need_time; for(i=0;i<K;i++) windows[i].next_available_time=3600*8;//都先初始化为8点 int len=0; for(i=0;i<N;i++) { int h,m,s; scanf("%s%d",arrive_time,&need_time); if(strcmp(arrive_time,"17:00:00")>0) continue; sscanf(arrive_time,"%d:%d:%d",&h,&m,&s); if(h<8) wait_time+=8*3600-(3600*h+60*m+s);//把所有八点前的顾客到八点的时间都累计,当作都是八点到的 customer[len].arrive_time=3600*h+60*m+s; customer[len++].need_time=need_time*60; } N=len; sort(customer,customer+N,cmp); for(i=0;i<N;i++) { int w=find_available_windows(customer[i].arrive_time); if(w>=0) {//找到空闲窗口 // windows[w].next_available_time=customer[i].arrive_time+customer[i].need_time; if(customer[i].arrive_time<8*3600) { windows[w].next_available_time=8*3600+customer[i].need_time; } else { windows[w].next_available_time=customer[i].arrive_time+customer[i].need_time; } } else { //找不到空闲窗口 w=find_earliest_window(); /* wait_time+=windows[w].next_available_time-customer[i].arrive_time; * windows[w].next_available_time=(windows[w].next_available_time-customer[i].arrive_time)+customer[i].need_time; */ if(customer[i].arrive_time<8*3600) {//如果到得早 窗口的下个可用时间等于当前下个可用时间加新来顾客所需要服务时间 wait_time+=windows[w].next_available_time-8*3600; windows[w].next_available_time=windows[w].next_available_time+customer[i].need_time; } else { wait_time+=windows[w].next_available_time-customer[i].arrive_time; windows[w].next_available_time=windows[w].next_available_time+customer[i].need_time; } } } printf("%.1f\n",1.0*wait_time/60.0/N); }这里可以看到,王道的代码中是直接找出下一个可用的时间点,然后累加到等待时间总和中,这样它的时间是跳着来的,肯定要比按时间一秒一秒增加得要快得多。
——Apie陈小旭