题意:
银行里由N个窗口,每个窗口前可容纳M个人等待;
N*M之后的人需要在黄线以外等待寻找最短且序号最小的窗口进入等待;
现告诉你K个人办理业务需要的时间time_cost,试问其中Q个人的离开时间为多少。
已知银行8:00开始接待客户,17:00停止接待。
思路:
显而可见,前N*M个人分别按照1~N,1~N……的顺序进入窗口,之后就是黄线内的N*M个人离开一个,黄线外的客户进入该窗口。
设置N个queue模拟N个窗口,定义统一是时间线timeLine,每次寻找N个窗口头部耗时最短的用时minn_cost,将N个窗口头部的用户time_cost都减去该minn_cost(如果当前用户剩余的耗时为0则结束业务处理得到离开时间),再更新N个queue的头部(将耗时为0的用户pop掉)。
坑点:用户在16:59及以前开始处理业务的都能正常离开,而17:00及以后开始的业务才会"Sorry"。
实现代码:
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 1e3+10;
int n, m, k, q;
int time_cost[N], time_cost_back[N], cnt, timeLine;
queue<int> que[21];
map<int, string> ans;
string to_time(int idx, int time){
string res;
time += 8*60;
if(time-time_cost_back[idx]>=17*60) return "Sorry";
if(time/60<10) res += "0";
res += to_string(time/60)+":";
if(time%60<10) res += "0";
res += to_string(time%60);
return res;
}
int findMin(){
int minn = INT_MAX, res = -1;
for(int i = 1; i <= n; i ++){
if(que[i].size()==0) continue;
if(time_cost[que[i].front()]<minn){
minn = time_cost[que[i].front()];
res = que[i].front();
}
}
return res;
}
void update(){
for(int i = 1; i <= n; i ++){
if(que[i].size()==0) continue;
if(time_cost[que[i].front()]==0){
que[i].pop();
if(cnt<k) que[i].push(++cnt);
}
}
}
signed main()
{
cin >> n >> m >> k >> q;
for(int i = 1; i <= k; i ++){
cin >> time_cost[i];
time_cost_back[i] = time_cost[i];
}
bool flag = 0;
for(int i = 1; i <= m; i ++){
for(int j = 1; j <= n; j ++){
if(cnt>k){
flag = 1;
break;
}
que[j].push(++cnt);
}
if(flag) break;
}
while(true){
int idx = findMin();
if(idx==-1) break;
int del = time_cost[idx];
timeLine += del;
for(int i = 1; i <= n; i ++){
if(que[i].size()==0) continue;
time_cost[que[i].front()] -= del;
if(time_cost[que[i].front()]==0){
ans[que[i].front()] = to_time(que[i].front(), timeLine);
}
}
update();
}
while(q--){
int x; cin >> x;
cout << ans[x] << endl;
}
return 0;
}