排队“夹塞”是引起大家强烈不满的行为,但是这种现象时常存在。在银行的单窗口排队问题中,假设银行只有1个窗口提供服务,所有顾客按到达时间排成一条长龙。当窗口空闲时,下一位顾客即去该窗口处理事务。此时如果已知第i位顾客与排在后面的第j位顾客是好朋友,并且愿意替朋友办理事务的话,那么第i位顾客的事务处理时间就是自己的事务加朋友的事务所耗时间的总和。在这种情况下,顾客的等待时间就可能被影响。假设所有人到达银行时,若没有空窗口,都会请求排在最前面的朋友帮忙(包括正在窗口接受服务的朋友);当有不止一位朋友请求某位顾客帮忙时,该顾客会根据自己朋友请求的顺序来依次处理事务。试编写程序模拟这种现象,并计算顾客的平均等待时间。
输入格式:
输入的第一行是两个整数:1≤N≤10000,为顾客总数;0≤M≤100,为彼此不相交的朋友圈子个数。若M非0,则此后M行,每行先给出正整数2≤L≤100,代表该圈子里朋友的总数,随后给出该朋友圈里的L位朋友的名字。名字由3个大写英文字母组成,名字间用1个空格分隔。最后N行给出N位顾客的姓名、到达时间T和事务处理时间P(以分钟为单位),之间用1个空格分隔。简单起见,这里假设顾客信息是按照到达时间先后顺序给出的(有并列时间的按照给出顺序排队),并且假设每个事务最多占用窗口服务60分钟(如果超过则按60分钟计算)。
输出格式:
按顾客接受服务的顺序输出顾客名字,每个名字占1行。最后一行输出所有顾客的平均等待时间,保留到小数点后1位。
输入样例:
6 2
3 ANN BOB JOE
2 JIM ZOE
JIM 0 20
BOB 0 15
ANN 0 30
AMY 0 2
ZOE 1 61
JOE 3 10
输出样例:
JIM
ZOE
BOB
ANN
JOE
AMY
75.2
#include<iostream>
#include<cstdio>
using namespace std;
int n,m;
/*
* 构建圈子
* */
int cir1[10005];//每个圈子的人数
int cir11[10005];//打标记,
int cir22[10005] = {0};//打标记,就是看是否可以继续让下一个人用
string que1[10005];//输出的队列
string s1[105][105];//第一次的圈子,也就是原声圈子
string s2[105][105];//第二次输出的圈子,就是保存的结果
int cnt = 0,cnt1 = 0,cnt2 = 0;//备用计数器
int result = 0;//完成时间
double endTime = 0;
/*
* 构建个人
* */
struct Person{
string name;
int cir;//所在的圈子
int arrive;
int time;
}person[10005];
/*
* 构建圈子的函数
* */
void BuildCir(){
int x;
int count = 0;
cin>>n>>m;
for(int i = 0;i < m;i++){
cin>>x;
cir1[i] = x;//每个圈子有多少人
for(int j = 0;j < x;j++){
cin>>s1[i][j];//每个圈子里的具体的人数
}
}
}
/*
* find 函数
* */
int find(string name){
for(int i = 0;i < m;i++){
for(int j = 0;j < cir1[i];j++){ //cir1[i]表示这个圈子有多少人
if(s1[i][j] == name){
return i;
}
}
}
return -1;
}
int main(){
BuildCir();//构建好圈子
for(int i = 0;i < n;i++){
cin>>person[i].name>>person[i].arrive>>person[i].time;
if(person[i].time > 60)
person[i].time = 60;
person[i].cir = find(person[i].name);
}//队列输入完毕
int que[10005] = {0};//打标记,看看那个备选了 /*这个位置坑惨我了,天啊,一定要注意数据的范围啊*/
for(int i = 0;i < n;i++){
//cout<<person[i].name<<' '<<person[i].arrive<<' '<<person[i].time<<' '<<person[i].cir<<endl;
if(person[i].cir != -1 && cir22[i] != 1 && que[i] == 0){ //是圈子里的人,但是圈子还没出现,并且人也没入队
que1[cnt++] = person[i].name;//入队
cir22[i] = 1;//圈子出现
que[i] = 1;
if(result >= person[i].arrive){//表示要排队等待
endTime += result - person[i].arrive;
//cout<<result <<'*'<< person[i].arrive<<endl;
result += person[i].time;
//cout<<endTime<<endl;
}else { //不需要排队等待
result = person[i].arrive + person[i].time;
}
for(int j = i+1;j < n;j++){
if(person[j].cir == person[i].cir){ //找同圈子里的人
if(person[j].arrive <= result){//这种情况下可以插队
endTime += result - person[j].arrive;
//cout<<result <<'*'<< person[j].arrive<<endl;
que1[cnt++] = person[j].name;
que[j] = 1;
result += person[j].time;
//cout<<endTime<<endl;
}else{//不能插队
cir22[i] = 0;//这个圈子拿出来重新排队
break;//不再继续往后找
}
}
}
}else if(person[i].cir == -1){
que1[cnt++] = person[i].name;//入队
if(result >= person[i].arrive){//表示要排队等待
endTime += result - person[i].arrive;
//cout<<result <<'*'<< person[i].arrive<<endl;
result += person[i].time;
//cout<<endTime<<endl;
}else { //不需要排队等待
result = person[i].arrive + person[i].time;
}
}
}
for(int i = 0;i < cnt;i++){
cout<<que1[i]<<endl;
}printf("%.1lf\n",endTime/n);
return 0;
}