这篇博文记录下这题的解题过程,主要留由自己日后总结复习……
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
思路:模拟题,既然是排队的问题,自然想到用队列来做。
一开始构造队列的时候出了问题,犯了很多现在看来很滑稽的错误。
queue<queue<int> >q(n);
queue<queue<int> >q[n];
因为有n个窗口,所以想设n个队列,但是由于队列不支持随机访问,所以最外层定不可能用queue来存储……后来改成了:
vector<queue<int> >v(n);
还是对STL掌握的不够……(因为最简单的方法就是之间用queue型的数组,不用vector……)
然后就是按照题目所给的条件来模拟,我的方法是按照时间从8点到17点依次遍历,每次让n个队列的队首元素值减1(队列存储的是顾客办公所需要的时间),当时间为0时,说明事情处理完毕,弹出这名顾客,压入新的顾客放在队列尾部。循环过程中记得每次要判断队列是否为空,对于空队列要跳过而不是读取它的队首元素。
坑点:这点我也是看了别人的分析才明白的,题目要查询的顾客,只要在五点银行下班前排到了ta,那么ta的业务就是要处理完的并且是可查询的。我一开始以为只要在17点之后才能办完业务的顾客全输出Sorry,仔细读题目才发现是不对的。
代码如下:(有逻辑错误)
(这里为了方便操作,我把时间全部化为分钟,8点是480分,17点是1020分。)
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 1005;
struct customer { //一开始并没有用结构体,但是仅用数组下标表示顾客编号的话会有问题
int id; //问题在于将顾客压入队列后,就会丢失顾客的编号,所以还是用了结构体
int cost;
};
int main() {
int n, m, k, q;
customer a[maxn];
scanf("%d %d %d %d", &n, &m, &k, &q);
for (int i = 1; i <= k; i++) {
scanf("%d", &a[i].cost);
a[i].id = i;
}
int query[maxn];
for (int i = 0; i < q; i++) {
scanf("%d", &query[i]);
}
vector<queue<customer> >v(n);
int served[maxn]; //这个数组用来存储顾客开始被办理业务的时间
fill(served, served + maxn, 1030);
int cnt = 1;
for (int i = 0; i < m; i++) //模仿银行8点开门时,顾客开始排队
for (int j = 0; j < n; j++) {
v[j].push(a[cnt++]);
served[cnt - 1] = 480;//这里也有问题,8点开始排队并不代表此时开始办事
}
int time;
int comple[maxn]; //这个数组用来存储顾客办理业务结束的时间
fill(comple, comple + maxn, 1030); //这里有错误
int completed = 0; //用来计数
//cnt = n * m + 1;
for (time = 480; time <= 1020; time++) {
for (int i = 0; i < n; i++)
if (v[i].size() != 0) { //队列非空才能操作
v[i].front().cost--; //这里注意到front()返回的是队首元素的引用,所以才可以这么操作
if (v[i].front().cost == 0) { //办理完了则弹出
comple[v[i].front().id] = time + 1; //记录结束的时间
v[i].pop();
if (!v[i].empty())
served[v[i].front().id] = time + 1; //记录开始的时间
if (cnt <= k) { //还有顾客在黄线外的话就压入队列
v[i].push(a[cnt++]);
}
}
}
}
for (int i = 0; i < q; i++) {
if (served[query[i]] >= 1020) //这里的=号不能丢
printf("Sorry\n");
else
printf("%02d:%02d\n", comple[query[i]] / 60, comple[query[i]] % 60);
}
return 0;
}
这段代码有好多细节上的问题以及一个逻辑上的漏洞。可是没想到居然AC了= =……问题就在
fill(comple, comple + maxn, 1030);
这句上。最后那个参数原本只要足够大即可,说明顾客的业务结束时间是在17点之后的。不知怎的,我当时莫名其妙的选择了1030这个数字,没想到正好撞上了最后一个测试点。如果你把这个改为1031,那么会显示最后一个测试点不通过 = = ……这个也是我提交通过之后才发现的,当时就觉得自己的代码并没有写完,对于17点之后的顾客没有求出ta们业务结束的时间(因为循环在17点就停止了),原来是自己瞎猫碰见死耗子了……
修改后的代码:
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 1005;
struct customer {
int id;
int cost;
};
int main() {
customer a[maxn];
int n, m, k, q;
scanf("%d %d %d %d", &n, &m, &k, &q);
for (int i = 1; i <= k; i++) {
scanf("%d", &a[i].cost);
a[i].id = i;
}
int query[maxn];
for (int i = 0; i < q; i++) {
scanf("%d", &query[i]);
}
int served[maxn];
fill(served, served + maxn, 1030);
vector<queue<customer> >v(n);
int cnt = 1;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
v[j].push(a[cnt++]);
served[j + 1] = 480;
}
}
int completed[maxn];
fill(completed, completed + maxn, 9999);
int completed_cnt = 0;
for (int time = 481; time <= 9999; time++) {
for (int i = 0; i < n; i++) {
if (!v[i].empty()) {
v[i].front().cost--;
if (v[i].front().cost == 0) {
completed[v[i].front().id] = time;
v[i].pop();
if (!v[i].empty())
served[v[i].front().id] = time;
if (cnt <= k) {
v[i].push(a[cnt++]);
}
}
}
}
}
for (int i = 0; i < q; i++) {
if (served[query[i]] >= 1020)
printf("Sorry\n");
else
printf("%02d:%02d\n", completed[query[i]] / 60, completed[query[i]] % 60);
}
return 0;
}
检查了几遍,逻辑上应该是没有问题了。优化了数组的命名,还有循环时间应该从8点01开始而不是8点整。最后优化过的代码我没有加注释,思路在上面的那段中已经展现的很清楚了。