PAT 1014

题目

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:

  1. 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.
  2. 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.
  3. 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, 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

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

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

整个题目就是一个模拟银行早上排队的过程,需要计算输出每个人被服务完成的时间,如果超过了17:00就不服务。

代码及思路

思路

本题基于一个特定的事实

 不论题目给多少人,给多少窗口,在读入所有数据的时候,其实每位顾客所被服务的窗口和结束服务的时间

都是确定的,所以一定要一次性将所有的顾客排好队。(黄线内的顾客只看哪个队伍人少,即从0 ~ n - 1依次

进入窗口)(黄线外的顾客只看时间少,即那个窗口先出来空就去哪儿)。这样就需要有两种读入数据和初

始化窗口的路径。

代码

#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;

const int MAX = 1111;
int n, m, k, query, q;
int convertToMinute(int h, int m) {
	return h * 60 + m;
}

struct windows {
	int endTime, popTime;
	queue<int> q;
}windows[20];
int ans[MAX], needTime[MAX];

int main() {
	int index = 0;
	scanf_s("%d %d %d %d", &n, &m, &k, &query);
	for (int i = 0; i < k; i++) {
		scanf_s("%d", &needTime[i]);
	}
	//先将窗口内的popTime和endTime初始化为8:00
	for (int i = 0; i < n; i++) {
		windows[i].endTime = windows[i].popTime = convertToMinute(8, 0);
	}
	//限度如一部分客户(如果客户比窗口承载少则这一步直接读完所有客户,如果客户大于窗口承载,则这一步先读满窗口)
	for (int i = 0; i < min(n * m, k);  i++) {
		//先入队,在不考虑黄线外的人的情况下,对n取余就是这个人应该去的地方
		windows[index % n].q.push(index);
		//更新服务时间endTime
		windows[index % n].endTime += needTime[index];
		//更新第一个客户服务结束时间
		if (index < n) {     //目前用户的标号小于窗口总数证明他总是该窗口的第一个人
			windows[index % n].popTime = needTime[index];
		}
		ans[index] = windows[index % n].endTime;
		index++;
	}
	for (; index < k; index++) {
		int minpopIime = 540;
		int flag;
		//找出来第一个服务完客户的窗口
		for (int i = 0; i < n; i++) {
			if (windows[i].popTime < minpopIime) {
				flag = i;
				minpopIime = windows[i].popTime;
			}
		}
		windows[flag].q.pop();
		windows[flag].q.push(index);
		windows[flag].endTime += needTime[index];
		windows[flag].popTime += needTime[windows[flag].q.front()];
		ans[index] = windows[flag].endTime;
	}
	for (int i = 0; i < query; i++) {
		scanf_s("%d", &q);
		//用户从1开始
		if (ans[q - 1] - needTime[q - 1] >= convertToMinute(17, 0)) {
			printf("Sorry!\n");
		}
		else {
			printf("%02d:%02d\n", ans[q - 1] / 60, ans[q - 1] % 60);
		}
	}
	return 0;
}

上述代码来源于晴神算法笔记,其中对于很多细节的处理十分巧妙,非常值得学习。

  1. 定义窗口结构体。一开始时,将结构体定义为了顾客,其中存储了顾客所需要的时间,顾客完成时间和顾客所在队列(窗口)编号。但是在读入的过程中遇到了很大问题,比如顾客所在窗口编号在所有窗口都满的时候,计算被服务完成的时间需要不断计算更新窗口內所有人的服务时间,做了大量重复计算。所以可以将结构体定义为

    struct windows {
    	int endTime, popTime;
    	queue<int> q;
    }windows[20];
    

    这样的话可以根据读入的时候不断更新记录,可以通过下标直接访问结构体从而得到所需要的总时间。

  2. 使用取余来得到每个顾客所在的队列。在窗口未满的情况下,每个顾客所在下标对窗口号取余就是他该去的窗口(在读入的过程中,窗口和顾客都是从0开始读,这样的话取余操作才简单有效)。

  3. 在更新黄线外的人进队列的操作时候,记得所有的时间都是“加”而不是“替代” (我自己做的时候就将把“加的操作变为了更新,导致结果很乱 ”)。因为本题所处环境在时间维度上讨论,并不是说第一个人用三分钟出队之后下一个人还是从8:00开始计时。本题初始化的时候将出入时间都变为了8:00,代码体现如下

    windows[flag].endTime += needTime[index];
    windows[flag].popTime += needTime[windows[flag].q.front()];
    
  4. 将所有时间转换为分钟,方便计算比较。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值