#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<string.h>
#include<cmath>
#include<string>
using namespace std;
//跪在题意理解(搜索树构建)和代码错误
/*************************
题意:
有N个窗口,每个窗口可排队M个人。
排不进去的人在黄线外等待。
只要队伍有空隙,就可排入,选序号最小的队伍排入。
17点以及17点之后停止“开始服务”
即17点以及17点之后不准开始新的服务
但是17点之前的服务是可以进行到完成的。。。尼马题目好坑啊
*************************/
/************************
求解要点:
1.先把每个队列排满人,接着再按每个队头最先出队者,进行遍历,每次出队,一定有一个人可以插进来,并计算队头的出队时间
以及最后判断是否不可服务,注意题目陷阱
************************/
/***********************
笔记:
*********************/
#define M 1200
#define INF 0xfffffff
int cust[M];
struct WinQ{
queue<int> q;
int outtime;
int id;
};
WinQ wq[M];
int cusqt[M];
int main()
{
int n,m,k,q,i,ci;
scanf("%d%d%d%d",&n,&m,&k,&q);
queue<int> yq;
int qmax=m;
for(i=0;i<k;i++)
{
scanf("%d",&cust[i]);
yq.push(i);
}
int cus;
//安排前N个顾客
for(i=0;i<n;i++)
{
wq[i].outtime=INF;
if(!yq.empty())
{
ci=yq.front();
yq.pop();
wq[i].q.push(ci);
wq[i].outtime = cust[ci];
}
}
//把人排满队伍先
while(wq[n-1].q.size()<qmax && !yq.empty())
{
for(i=0;!yq.empty() && i<n;i++)
{
if(wq[i].q.size()<qmax)
{
ci=yq.front();
yq.pop();
wq[i].q.push(ci);
}
}
}
int tmin,id,lmin;
while(1)
{
//以出队时间排序。不用考虑序号和长度
//只要当前只有该队出队,则一定有人补上或后面没人补了
tmin=INF;
for(i=0;i<n;i++)
{
if(wq[i].outtime<tmin)
{
tmin=wq[i].outtime;
id=i;
lmin=wq[i].q.size();
}
}
//队伍全空,则break
if(tmin==INF)
break;
//计算出队时间
ci=wq[id].q.front();
cusqt[ci]=wq[id].outtime;
wq[id].q.pop();
//选等待者入队
if(!yq.empty())
{
ci=yq.front();
yq.pop();
wq[id].q.push(ci);
}
//出队时间增加
//若已空队说明没人等待了,取消服务。
if(wq[id].q.empty())
wq[id].outtime=INF;
else
wq[id].outtime += cust[wq[id].q.front()];
}
int quest,h,custime;
for(i=0;i<q;i++)
{
scanf("%d",&ci);
custime=cusqt[ci-1]; //结束服务时间
//结束服务时间-所花时间=开始时间,开始时间在17点及17点之后的为sorry
if(custime -cust[ci-1] < 540) //注意是小于0
{
h=custime/60 + 8;
m=custime%60;
printf("%02d:%02d\n",h,m);
}
else printf("Sorry\n");
}
return 0;
}
二刷时的代码:
/*************************
题意:
给出前序和中序遍历
求后序遍历的第一个点
************************/
/***********************
解题思路:
用递归
先在前序里找出本次递归子树的root
然后在中序里找出root的位置
如果有左树,则去左树里递归
如果没有左树,则去右树里递归
递归到第一个叶子,则那个就是后序的第一个点
*************************/
/***********************
笔记:
*********************/
#include<iostream>
#include<stdio.h>
#include<string>
#include<vector>
#include<queue>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<stack>
#include<map>
#include<set>
#include<unordered_map>
using namespace std;
#define M 10000
#define INF 0x7ffffff
int waitt[M];
int cendt[M];
int qendt[M];
int main(){
int n,m,k,q;
int i,j;
cin>>n>>m>>k>>q;
int ci = 1, select, tmin;
queue<int> cq[M];
j = 0;
for(i = 1;i <= k;i++){
scanf("%d", &waitt[i]);
//大家第一时间把队伍填满
if(i <= m*n){
ci++; //ci代表排在最前面的未入队者
cq[j].push(i); //按窗口序号轮流入队
j = (j+1)%n;
}
}
for(i=0;i<n;i++){
if(!cq[i].empty())
qendt[i] = 8*60 + waitt[cq[i].front()];
cendt[cq[i].front()] = qendt[i];
}
int qnum[M];
memset(qnum,0,sizeof(qnum));
int nmin;
//出队k次
for(j = 0;j < k;j++){
tmin = INF;
for(i = 0;i < n;i++){
if(qendt[i] < tmin){
tmin = qendt[i];
select = i;
}
}
cq[select].pop();
if(ci <= k) //未入队者还有,则入队,否则不入。
cq[select].push(ci++);
if(!cq[select].empty()){
qendt[select] += waitt[cq[select].front()];
cendt[cq[select].front()] = qendt[select];
}
else qendt[select] = INF;
}
int qi;
for(i = 0;i < q;i++){
scanf("%d",&qi);
if(cendt[qi] - waitt[qi]< 17*60)
printf("%02d:%02d\n", cendt[qi]/60, cendt[qi]%60);
else printf("Sorry\n");
}
return 0;
}