1017. Queueing at Bank (25)

1017. Queueing at Bank (25)

时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

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 10
Sample Output:
8.2

类型:模拟

题目大意:有n个客户,k个窗口。已知每个客户的到达时间和需要的时长(不超过60min,超过的会被压缩成60min),如果有窗口就依次过去,如果没有窗口就在黄线外等候(黄线外只有一个队伍,先来先服务),求客户的平均等待时长。银行开放时间为8点到17点,再8点之前不开门,8点之前来的人都要等待,在17点后来的人不被服务。

(1)自己写的

/*
1、注意这里时间间隔统一换算成秒,而不是分钟,因为转换成分钟中间要除以60,数值会损失,降低精度
这个问题很重要,之前就是因为这个问题最后一个案例无法通过。
2、如果客户到达的时间比队列结束的早,需要等待,队列时间为上次上次服务时间加上这次服务时间
3、如果客户到达的时间比队列结束的晚,则不需等待,队列结束时间为客户到达时间加上服务时间 
4、如果在8点前来的,就需要等到8点。如果17点以后来的,则不会被服务,无需考虑。 
*/
#include<iostream>
#include<algorithm>	
using namespace std;
struct node
{
	int hh;
	int mm;
	int ss;
	int time;//所需秒数 
	int come;//到达时间,统一用秒表示 
}peo[10001];
int endtime[101];//表示每个队列的出队时间 
int cmp(const node &a,const node &b)
{
	if(a.hh!=b.hh)
		return a.hh<b.hh;
	else if(a.mm!=b.mm)
		return a.mm<b.mm;
	else
	return a.ss<b.ss;
}
int n,k;
int sumtime=0;//总的延迟秒数 
int main()
{
	//freopen("in.txt","r",stdin);
	cin>>n>>k;
	for(int i=0;i<n;++i)
	{
		scanf("%d:%d:%d %d",&peo[i].hh,&peo[i].mm,&peo[i].ss,&peo[i].time);
		peo[i].come=3600*peo[i].hh+60*peo[i].mm+peo[i].ss;
		if(peo[i].time>60)//不能超过一小时 
			peo[i].time=3600;
		else
		peo[i].time*=60;//转换成秒 
	}
	sort(peo,peo+n,cmp);
	fill(endtime,endtime+101,28800);//数组初始化 
	int index=0;//记录参加平均时间计算的人数 
	for(int i=0;i<n;++i)
	{
		if(peo[i].come>61200)//17:00之后来的,后面及其自己不考虑 
			break;
		int early=endtime[0];
		int best=0;
		++index; 
		for(int j=1;j<k;++j)
		{
			if(endtime[j]<early)
			{
				early=endtime[j];
				best=j;
			}
		}
		if(endtime[best]>peo[i].come)//如果来的时间比队列结束时间还迟,等待时间为0 
		{
			sumtime+=endtime[best]-peo[i].come;
			endtime[best]+=peo[i].time;
		}
		else//来的时间比结束的迟,则排队的结束时间需要更新(***重要***) 
		endtime[best]=peo[i].come+peo[i].time;
	}
	if(index>0)
	printf("%.1f",sumtime/index/60.0);
	else cout<<"0.0";
	return 0;
} 

(2)别人的不错代码

分析:客户结构体node,里面有come为到达时间和time为需要服务的时长。先将所有满足条件的(到来时间点在17点之前的)客户放入数组中,数组的长度就是需要服务的客户的个数。window数组表示某个窗口的结束时间,每一个客户到来的时候,选择最早结束时间的窗口,如果最早结束时间比他还早,那么他一来就能被服务,更新window的值;如果最早结束时间比他晚,他需要等待,累加等待的时间,然后更新window的值。
一开始所有窗口的值都为8点整。对所有客户要先进行排序,按来的时间的早晚排序,之后再先来先服务。因为涉及分钟和秒数,可以把所有时间暂时先化解成秒数的形式,便于计算。如果一个可以被服务的客户都没有,需要直接输出0.0,因为任何数除以0都没有意义。

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
struct node {
    int come, time;
} tempcustomer;
bool cmp1(node a, node b) {
    return a.come < b.come;
}
int main() {
    int n, k;
    scanf("%d%d", &n, &k);
    vector<node> custom;
    for(int i = 0; i < n; i++) {
        int hh, mm, ss, time;
        scanf("%d:%d:%d %d", &hh, &mm, &ss, &time);
        if(time > 60)
            time = 60;
        int cometime = hh * 3600 + mm * 60 + ss;
        if(cometime > 61200)
            continue;
        tempcustomer.come = cometime;
        tempcustomer.time = time * 60;
        custom.push_back(tempcustomer);
    }
    sort(custom.begin(), custom.end(), cmp1);
    vector<int> window(k, 28800);
    double result = 0.0;
    for(int i = 0; i < custom.size(); i++) {
        int tempindex = 0, minfinish = window[0];
        for(int j = 1; j < k; j++) {
            if(minfinish > window[j]) {
                minfinish = window[j];
                tempindex = j;
            }
        }
        if(window[tempindex] <= custom[i].come) {
            window[tempindex] = custom[i].come + custom[i].time;
        } else {
            result += (window[tempindex] - custom[i].come);
            window[tempindex] += custom[i].time;
        }
    }
    if(custom.size() == 0)
        printf("0.0");
    else
        printf("%.1f", result / 60.0 / custom.size());
    return 0;
}

(3)

#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;  
}  
(4) 其实更好的办法的用窗口来,王道的代码如下:这里可以看到,王道的代码中是直接找出下一个可用的时间点,然后累加到等待时间总和中,这样它的时间是跳着来的,肯定要比按时间一秒一秒增加得要快得多。

#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);  
 }  



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值