排队“夹塞”是引起大家强烈不满的行为,但是这种现象时常存在。在银行的单窗口排队问题中,假设银行只有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
思路:
两个结构体数组,按题意模拟,代码比较复杂,一定要先用样例模拟一遍保证逻辑
注意点:
1.要设置顾客是否已经处理的判断条件
2.等待时间的计算一定要在窗口时间计算的前面
代码:
#include <stdio.h>
#include <string.h>
#define maxsize 100001
struct friends
{
char fri[maxsize][4];
}circle[101]; // 朋友圈
struct QueueData
{
char name[4];
int time;
int pime;
}queue[maxsize];
int s[maxsize];//判断顾客是否已经处理过,以处理用1表示
int len[101]; // 第几个圈子内有几个朋友
int main()
{
int n, m;
scanf("%d %d", &n, &m);
//若圈子不为0, m为圈子数
if(m)
{
for(int i=0; i<m; i++)
{
int l;
scanf("%d", &l);
len[i] = l;
for(int j=0; j<l; j++)
{ //输入圈子中的名字
scanf("%s", circle[i].fri[j]);
}
}
}
//输入所有顾客信息
for(int i=0; i<n; i++)
{
scanf("%s %d %d", queue[i].name, &queue[i].time, &queue[i].pime);
if(queue[i].pime > 60) queue[i].pime = 60;
}
// 计算
int sum_time = 0; //总共等待时间
int win_time = 0; //窗口完成时间
for(int i=0; i<n; i++)
{
if(s[i] == 0) //不是圈子里的且没有被处理的顾客
{
if(queue[i].time >= win_time)//不需要等待
{
win_time += (queue[i].time - win_time) + queue[i].pime;
}
else //需要等待
{
sum_time += win_time - queue[i].time;
win_time += queue[i].pime;
}
printf("%s\n", queue[i].name);
int flag = 0;//是否有圈子
int index = 0; //顾客所在的圈子位置
// 先判断queue[i]顾客所属哪个圈子,再夹塞
for(int j=0; j<m; j++)
{
for(int k=0; k<len[j]; k++)
{
if(strcmp(queue[i].name, circle[j].fri[k]) == 0)
{
flag = 1;
index = j;
break;
}
}
}
// 属于圈子, 判断后面的顾客有没有跟他是同圈子的
if(flag)
{
for(int j=i+1; j<n; j++)
{
for(int k=0; k<len[index]; k++)
{
if(strcmp(queue[j].name, circle[index].fri[k])==0 && s[j]==0)
{
if(queue[j].time > win_time) break; //夹塞顾客未在窗口完成时间内赶到
// 提前或者准时到达,进行夹塞操作
sum_time += win_time - queue[j].time;
win_time += queue[j].pime;
s[j] = 1;
printf("%s\n", queue[j].name);//输出夹塞顾客
}
}
}
}
}
s[i] = 1;
}
// 输出平均等待时间 小数点后一位
printf("%.1f", 1.0*sum_time/n);
return 0;
}