题意
有K个人需要办理业务,总共有n个窗口,每个窗口后面有一条黄线,窗口和黄线之间只能容纳m个人,黄线后面的人只排成一列,如果一旦前面排队的队伍有空位,那么就选择人数最少的一列,如果人数最少的一列有多种情况,就选择窗口最短的
思路
首先肯定是要用队列的,可以利用队列开成数组解决,我们每次扫描队列头,把队列头部人完成所需要消耗的时间,加上这个队列前面所有已经出队的时间,就是这个人出队伍的时间,我们扫描队首出队伍时间最短的,如果有多个,就选窗口号最小的,这样能保证这个人是最早出队的,那么在黄线外的人,肯定是去这个出队人所在的队伍。这样一直模拟就可以了。
坑点
Sorry的输出是指的是17点以后没到窗口的,不要理解为17点以后离开队列的。
反思
1题意开始,最后又一个地方没有读清楚,导致输出有问题
2最开始实现想的太复杂,应该多想使得问题简单化,不熟悉的东西就不要用。
3优先队列嵌套pair<int,int> 默认是首先第一个关键字从大到小,然后是第二个关键字从大到小
代码
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<vector>
#define LL long long
#define pii pair<int,int>
#define mp make_pair
using namespace std;
const int INF = 0x3f3f3f3f;
queue<int>que[24];
int line[25][1006];
int top[25];
int pre[24];
int n,m,k,qq;
int a[300004];
int ans[300005];
int sz[25];
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("in.txt","r",stdin);
#endif
while(~scanf("%d%d%d%d",&n,&m,&k,&qq)){
int tmp;
for (int i=1;i<=n;i++){
while(que[i].size())que[i].pop();
}
memset(pre,0,sizeof(pre));
for (int i=1;i<=k;i++){
scanf("%d",&a[i]);
}
int tot=0;
for (int j=1;j<=m;j++){
for (int i=1;i<=n;i++){
tot++;
if (tot>k)break;
que[i].push(tot);
}
}
int flag=0;
while(flag==0){
int minn=INF;
int w=INF;
int pos=0;
for (int i=1;i<=n;i++){
if (que[i].size() && pre[i]+a[que[i].front()]<minn){
minn=pre[i]+a[que[i].front()];
w=a[que[i].front()];
pos=i;
}else if (que[i].size() && pre[i]+a[que[i].front()]==minn && pos>i){
pos=i;
}
}
if (minn!=INF){
if (pre[pos]<540)
ans[que[pos].front()]=pre[pos]+w;
que[pos].pop();
pre[pos]+=w;
if (tot<k){
tot++;
que[pos].push(tot);
}
}else{
flag=1;
}
}
while(qq--){
scanf("%d",&tmp);
int h=(ans[tmp]/60+8)%24;
int mins=ans[tmp]%60;
if (ans[tmp]!=0){
printf("%02d:%02d\n",h,mins);
}else{
printf("Sorry\n");
}
}
}
return 0;
}