题意: 银行柜台有N个,每个柜台可以独立干活排队。
每个柜台后面黄线内可以排队,可以排M个人。如果人满了,要么去别的队伍,要么去旁边等着。
一共有K个客户。每个客户自行去排队,客户排队的时候,会选择最快的队伍!每个客户需要Ti的时间处理业务。队伍前面的客户业务办完了,后面的客户办。
银行早上8点开始上班,下午17点关门。
输入Q此询问,每次输出特定的客户,什么时候能够完成业务滚出银行,如果这个人在银行下班了还没有来得及被受理业务,就输出Sorry。
难点:没想到吧,这就是一道模拟题!然鹅难以下手,因为题目冗长的恶心,以及柜台各自成队伍。写了好几次,样例都过不了,本来用的是priority_queue,最后发现是用普通的队列即可。
后来参照了柳神的代码,好短啊。。。为什么我写的又臭又长。。。
没有细看柳神的代码,再次重写本题代码。
遇见的几个剧毒的坑:
1、客户选哪个队伍,并不是“上帝视角”!他们是不知道别人的业务要办理多久的!所以,客户选人,只会看哪条队伍可以哦排队了,就去哪条队伍。
2、柜台受理的工作时间定义:柜台在17:00分之前,都是受理的,不论你的业务多久!如果你的在16:59分办理60分钟的业务,柜台也会兢兢业业的帮你完成!但是在大于等于17:00分之后,就不受理了。
3、题目要求输出的是客户的业务完成时间,而不是业务受理时间。比如刚刚的例子,16:59分受理60分钟的业务,那么这个客户就输出17:59分,而不是16:59.
4、这个最大的毒瘤。。。WA了半天,找不到错误,逻辑没毛病,算法应该OK,为什么WA。一个样例过不了,多半是特例。两天以后,我才发现,测试数据里黄线内可容纳的人数,tm可以为0.。。。。为什么没有博客发现这一点。。心好累,此题有毒,你黄线内容纳的人数为0,那不是表示银行不干活了吗!通过这个测试点1的办法就是,把输入m为0特判一下,改成1即可。这也再次体现的我算法的差劲,柳神的代码都不需要特判的。。。
Code:
本人思路:
每个柜台都有一个队列;队首的客户完成业务的时间——用来给模拟客户选择,哪只柜台的队伍先空出来;当前队末客户业务完成的时间,用来计算输出的结果。
先把所有人都装入到黄线内,采用轮询的方式。同时计算维护柜台的参数,并计算这些人的时间答案。
再模拟剩下的客户排队的情况,算出剩下人的答案。
在输入的部分,特判了m==0的情况。
程序代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 1009
#define INF 0x3f3f3f3f
#define loop(x,y,z) for(x=y;x<z;x++)
int n,m,k,q;//柜台、线内、顾客、查询
int cost[inf];//顾客消耗时间
int ans[inf];//顾客完成时间
int maxTime=9*60;//最多等待时间9个小时
bool book[inf];//标记顾客来的来不及开始
struct Node
{
queue<int>q;
int time_first;//队首人什么时候出来,用于黄线外人选择
int time_end;//队尾这个人什么时候出来,用于记录终解
Node()
{
while(!q.empty())q.pop();
time_first=time_end=0;
}
}counter[22];//柜台
void Solve()//客户自0始
{
memset(book,0,sizeof book);
int i,j,index=0;
bool tag=true;//循环结束标记
while(index<k&&tag)//先把黄线内装满
{
tag=false;
loop(j,0,n)
if(counter[j].q.size()<m)//装入此人,并计算此人出来的时间
{
counter[j].q.push(index);
if(counter[j].time_end>=maxTime)book[index]=true;//判断前面的人完成的时候,是不是关门了
counter[j].time_end+=cost[index];//累加,计算自己什么时候出来
ans[index]=counter[j].time_end;//保存结果,以备输出
//printf("debug: %d\n",ans[index]);
index++;
tag=true;
}
}
loop(i,0,n)//柜台第一个人出来的时间
{
int t=counter[i].q.front();
counter[i].time_first=cost[t];//队首人走的时间
}
//开始计算每个人
while(index<k)
{
int tag=0;
loop(i,0,n)
if(counter[i].time_first<counter[tag].time_first)tag=i;//找出哪个队先走人
counter[tag].q.pop();//走一个
counter[tag].q.push(index);//进一个
if(counter[tag].time_end>=maxTime)book[index]=true;//判断前面的人完成的时候,是不是关门了
//printf("debug: %d\n",counter[tag].time_end);
counter[tag].time_end+=cost[index];//记录进去的人什么时候出来
ans[index]=counter[tag].time_end;
int top=counter[tag].q.front();
counter[tag].time_first+=cost[top];//更新下一个人出来的时间
index++;
}
}
void Input()
{
scanf("%d%d%d%d",&n,&m,&k,&q);
if(!m)m=1;
int i;
loop(i,0,k)scanf("%d",&cost[i]);
Solve();
int j;
loop(i,0,q)
{
scanf("%d",&j);
if(book[j-1])
printf("Sorry\n");
else
printf("%02d:%02d\n",8+(ans[j-1]/60),ans[j-1]%60);
}
}
int main()
{
Input();
return 0;
}