题目链接:
https://pintia.cn/problem-sets/994805342720868352/problems/994805498207911936
题目大意:
此题和patA1017在题目假设上是一致的,都是涉及K个顾客到银行中N个窗口的排队问题,其中,排队原则是:每个窗口即,队列最多一次可排N名顾客,且如果一旦入队则无法变动队列。当N个窗口没满时,当前第一个即将入队的人都会选择人数最少的队列,当存在多个相同长度的最短队列,则从编号最小的开始;已知银行的营业时间为早上八点到下午五点,因此如果某一顾客的开始服务时间为下午五点或者之后,则无法被服务。依次给出这K个顾客需要服务的时间,以分钟为单位,然后给出需要查询的顾客编号,输出对应顾客的结束服务时间,无法被服务,则输出sorry。需要注意的是,与patA1017不同的是,K个顾客已经按编号1~K排好序。
这是一个排队问题,那么显然需要设置N个窗口队列。
用两个int型数组ans,need分别保存对应编号的服务结束时间,以及服务时间。变量poptime记录队列队首顾客的结束时间,变量endtime记录队列队尾顾客的结束时间,初始化为早上八点,同时,需要设置队列q保存队伍中顾客的信息。设置结构体pnode保存窗口信息。为了省去时间进制转换的麻烦,不妨将时间转换成以分钟为单位的数值。
参考代码:
#include <cstdio>
#include <queue>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 1010;
int n, m, k, query, q;
int ans[maxn], need[maxn];
int convert(int h, int m){
return h*60 + m;
}
struct Pnode{
int endtime, poptime;
queue <int> q;
};
int main(){
int pos = 0; //当前第一个未入队编号
scanf("%d %d %d %d", &n, &m, &k, &query);
vector <Pnode> window(n);
for(int i = 0; i < k; i++){ //读入服务时间
scanf("%d",&need[i]);
}
for(int i = 0; i < n; i++){ //初始化每个窗口的endtime以及poptime;
window[i].endtime = window[i].poptime = convert(8, 0);
}
for(int i = 0; i < min(n*m, k); i++){ //循环入队,此时因为窗口前存在未满的队列,
window[pos%n].q.push(pos); //则以此入队列即可,需要更新队伍顾客信息q,
window[pos%n].endtime += need[pos]; //以及队伍结束时间
if(pos < n) window[pos].poptime = need[pos]; //若此顾客为当前队列第一个时,
//还需要更新队首的结束时间
ans[pos] = window[pos%n].endtime; //将编号为pos的顾客结束服务时间加入ans数组中。
pos++;
}
for(; pos < k; pos++){
int idx = -1, minpoptime = 1e9; //找出队首顾客最早结束服务的队列。
for(int i = 0; i < n; i++){
if(window[i].poptime < minpoptime){
idx = i;
minpoptime = window[i].poptime;
}
}
Pnode& W = window[idx];
W.q.pop();
W.q.push(pos); //将当前顾客入队,更新endtime以及poptime
W.endtime += need[pos];
W.poptime += need[W.q.front()];
ans[pos] = W.endtime;
}
for(int i = 0; i < query; i++){ //服务开始时间即 结束服务时间-服务时间
scanf("%d", &q);
if(ans[q - 1] - need[q - 1] >= convert(17, 0)) printf("Sorry\n");
else printf("%02d:%02d\n",ans[q-1]/60, ans[q - 1]%60);
}
return 0;
}