1014 Waiting in Line(模拟)

1014 Waiting in Line

0、题目

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.
  • Customeri will take Ti 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 Specification:

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 Specification:

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

1、大致题意

店铺早上 8:00~17:00 营业,有 k 个顾客,按照一定规则排队,输出业务办理完时间。具体规则如下:

  • 每个窗口前面的黄线内的空间只能容纳 m 个客户。因此,当所有 n 行都满时,(n*m+1) 后的所有客户(包括)都必须在黄线后面排队等候。
  • 每一位顾客在过黄线时都会选择最短的排队等候。如果有两条或两条以上相同长度的队,顾客总是会选择编号最小的窗口。
  • i 位顾客需要花费 T i T_i Ti 分钟办理他的业务

2、基本思路

整体思路就是使用优先队列来解题。

首先构建一个顾客的结构体 customer,具体如下:

struct customer {
	int windows;
	int time; //办理业务所需时间
	int start;
	int end;
	bool operator >(const customer &a)const {
		if(end!=a.end) {
			return end > a.end;
		} else {
			return windows > a.windows;
		}
	}
}

可以看到,我在上面结构体里加入了 > 的复写,便于使用优先队列。然后便是模拟业务办理的规则。

3、解题过程

3.1 优先队列相关知识

3.1.1 基本操作

具体写法如下:

//升序队列,小根堆
priority_queue <int,vector<int>,greater<int> > q;
//降序队列,大顶堆
priority_queue <int,vector<int>,less<int> >q;

//greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了)

和队列基本操作相同:

操作函数解释
top()访问队头元素
empty()队列是否为空
size()返回队列内元素个数
push()插入元素到队尾(并排序)
emplace()原地构造一个元素并插入队列
pop()弹出队头元素
swap()交换内容
3.1.2 和 struct 双剑合璧

STLstruct 一起操作起来是真的骚 yyds 。但是如果你想双剑合璧,还得学一份武林秘籍 —— 重载运算符

  • greater<> 要求重载 operator >
  • less<int> 要求重载 operator <
struct node {
    int l,r;
    bool operator <(const node &a)const{
        return r < a.r;
    }
} a[maxn];

3.2 第一份提交代码(19/30)

有了上面的思路,马上就有了第一份提交代码

#include<iostream>
#include<queue>
using namespace std;
struct customer {
	int windows;
	int time; //办理业务所需时间
	int end;
	bool operator >(const customer &a)const {
		return end > a.end;
	}
} cus[1005],tmp;

int n,m,k,q;
int wins[25];
int num;
priority_queue<customer,vector<customer>,greater<customer> >q1; //小顶堆
int main() {
	cin>>n>>m>>k>>q;
	for(int i=1; i<=n; i++) {
		wins[i]=0;
	}
	for(int i=1; i<=k; i++) {
		cin>>cus[i].time;
	}
	for(int i=1; i<=m; i++) {
		for(int j=1; j<=n; j++) {
			num=(i-1)*n+j; //(i-1)*n+j为cus的编号
			if(num<=k) {
				cus[num].windows=j;
				cus[num].end=wins[j]+cus[num].time;
				wins[j]=cus[num].end;
				q1.push(cus[num]);
			} else {
				break;
			}
		}
		if(num>k) {
			break;
		}
	}
	while(!q1.empty()&&num<=k) {
		tmp=q1.top();
		q1.pop();
		num++;
		int now=tmp.windows;
		cus[num].windows=now;
		cus[num].end=cus[num].time+wins[now];
		wins[now]=cus[num].end;
	}
	int ques;
	for(int i=1; i<=q; i++) {
		cin>>ques;
		if(cus[ques].end>540){
			cout<<"Sorry"<<endl;
		}else{
			int HH=cus[ques].end/60+8;
			int MM=cus[ques].end%60;
			printf("%02d:%02d\n",HH,MM);
		}
	}
	return 0;
}

在这里插入图片描述

3.3 测试点 2,4 - 第二份提交代码(26/30)

对于 2,4 的情况:一个人如果开始时间在540之前(不包括540)即使结束时间超过540,依旧要服务,例:一个人16:49 进入1号窗口办理业务,要办理 120 分钟,则他的完成时间为 18:49。比如下面这个用例:

输入:
2 2 3 3
539 539 6
1 2 3
输出:
16:59
16:59
17:05

这点其实也很容易做到,就是在 customer 中加入一个新元素 start 就行了

#include<iostream>
#include<queue>
#include<cmath>
using namespace std;
struct customer {
	int windows;
	int time; //办理业务所需时间
	int start;
	int end;
	bool operator >(const customer &a)const {
		if(end!=a.end) {
			return end > a.end;
		} else {
			return windows > a.windows;
		}
	}
} cus[1005],tmp;

int n,m,k,q;
int wins[25];
int num;
priority_queue<customer,vector<customer>,greater<customer> >q1; //小顶堆

int toTime(int t){ //防止上溢
	return min(1000,t);
}

int main() {
	cin>>n>>m>>k>>q;
	for(int i=1; i<=n; i++) {
		wins[i]=0;
	}
	for(int i=1; i<=k; i++) {
		cin>>cus[i].time;
	}
	for(int i=1; i<=m; i++) {
		for(int j=1; j<=n; j++) {
			num=(i-1)*n+j; //(i-1)*n+j为cus的编号
			if(num<=k) {
				cus[num].windows=j;
				cus[num].start=wins[j];
				cus[num].end=toTime(wins[j]+cus[num].time);
				wins[j]=cus[num].end;
				q1.push(cus[num]);
			} else {
				break;
			}
		}
		if(num>k) {
			break;
		}
	}
	while(!q1.empty()&&num<=k) {
		tmp=q1.top();
		q1.pop();
		num++;
		int now=tmp.windows;
		cus[num].windows=now;
		cus[num].start=wins[now];
		cus[num].end=toTime(cus[num].time+wins[now]);
		wins[now]=cus[num].end;
	}
	int ques;
	for(int i=1; i<=q; i++) {
		cin>>ques;
		if(cus[ques].start>=540) {
			cout<<"Sorry"<<endl;
		} else {
			int HH=cus[ques].end/60+8;
			int MM=cus[ques].end%60;
			printf("%02d:%02d\n",HH,MM);
		}
	}
	return 0;
}

在这里插入图片描述

3.4 测试点 5 - 第三份提交代码

还有个测试点5,真的自己测试了很久,找到了一个用例

输入:
1 1 3 3
539 100 6
1 2 3
正确输入:
16:59
18:39
Sorry
第二份提交代码:
16:59
18:39
08:00

问题出在哪里呢,调试了一遍后找到了,下面的代码中,少了注释的那一行。不然,当 q1 很少时,你不加入新的 customer ,甚至你都遍历不完所有的。

while(!q1.empty()&&num<=k) {
	tmp=q1.top();
	q1.pop();
	num++;
	int now=tmp.windows;
	cus[num].windows=now;
	cus[num].start=wins[now];
	cus[num].end=cus[num].time+wins[now];
	wins[now]=cus[num].end;
//		q1.push(cus[num]);
}

加上注释的那一行之后,终于 AC

3.5 奇葩想法

当然用我这种方法有个问题,就是下面这种用例的时候。

输入:
0 0 3 3
539 539 6
1 2 3
正确输出:
Sorry
Sorry
Sorry
第二份代码输出:
08:00
08:00
08:00

这个错误找了好久,nm 的取值为 0 一开始真是没有想到。

3.6 AC代码

#include<iostream>
#include<queue>
#include<cmath>
using namespace std;
struct customer {
	int windows;
	int time; //办理业务所需时间
	int start;
	int end;
	bool operator >(const customer &a)const {
		if(end!=a.end) {
			return end > a.end;
		} else {
			return windows > a.windows;
		}
	}
} cus[1005],tmp;

int n,m,k,q;
int wins[25];
int num;
priority_queue<customer,vector<customer>,greater<customer> >q1; //小顶堆

int toTime(int t) { //防止上溢
	return min(1000,t);
}

int main() {
	cin>>n>>m>>k>>q;
	for(int i=1; i<=n; i++) {
		wins[i]=0;
	}
	for(int i=1; i<=k; i++) {
		cin>>cus[i].time;
	}
	for(int i=1; i<=m; i++) {
		for(int j=1; j<=n; j++) {
			num=(i-1)*n+j; //(i-1)*n+j为cus的编号
			if(num<=k) {
				cus[num].windows=j;
				cus[num].start=wins[j];
				cus[num].end=wins[j]+cus[num].time;
				wins[j]=cus[num].end;
				q1.push(cus[num]);
			} else {
				break;
			}
		}
		if(num>k) {
			break;
		}
	}
	while(!q1.empty()&&num<=k) {
		tmp=q1.top();
		q1.pop();
		num++;
		int now=tmp.windows;
		cus[num].windows=now;
		cus[num].start=wins[now];
		cus[num].end=cus[num].time+wins[now];
		wins[now]=cus[num].end;
		q1.push(cus[num]);
	}
	int ques;
	for(int i=1; i<=q; i++) {
		cin>>ques;
		if(cus[ques].start>=540||n==0||m==0) {
			cout<<"Sorry"<<endl;
		} else {
			int HH=cus[ques].end/60+8;
			int MM=cus[ques].end%60;
			printf("%02d:%02d\n",HH,MM);
		}
	}
	return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值