银行排队问题之单窗口“夹塞”版 (30分)
题目描述:
排队“夹塞”是引起大家强烈不满的行为,但是这种现象时常存在。在银行的单窗口排队问题中,假设银行只有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 <bits/stdc++.h>
#define MaxNum 10010
using namespace std;
struct peo
{
string name;
int Start_Time;
int End_Time;
int Pos;
}People[MaxNum];//顾客信息
queue<peo>Customer; //记录排队的顾客
map<string,int>Friends; //朋友集
bool visited[MaxNum] = {false}; //记录顾客的状态
int main()
{
int N,M;
scanf("%d%d",&N,&M);
int i,j;
for(i = 0;i < M; ++i)
{
int num;
scanf("%d",&num);
for(j = 0;i < num; ++j)
{
string name;
scanf("%s",&name);
Friends[name] = i;
}
}
for(i = 0;i < N; ++i)
{
scanf("%s%d%d",&People[i].name,&People[i].Start_Time,&People[i].End_Time);
if(People[i].End_Time > 60)
People[i].End_Time = 60;
People[i].Pos = i;
Customer.push(People[i]);
}
int last = 0;
int result = 0;
while(!Customer.empty())
{
peo temp = Customer.front();
Customer.pop();
if(!visited[temp.Pos]) //没有办理过业务才进行
{
printf("%s\n",temp.name);
visited[temp.Pos] = true;
if(temp.Start_Time <= last) //如果一个人开始的时间小于最后一个人办完的时间,他就要等待
{
result += last-temp.Start_Time; //一个人他前面的最后一个人办完需要的时间 - 这个人来的时间 = 他要等待的时间
last += temp.End_Time; //更新办完当前业务需要的时间 (加上来这个人办业务需要的时间)
}
else
{
last = temp.End_Time+temp.Start_Time;
//如果一个人来的时候他前面的人都办完了,就不需要等待了,所以result+=0,不需要更新,只要更新办完当前事务的时间就行
}
for(i = temp.Pos+1 ; i < N ; ++i) //找朋友
{
if(People[i].Start_Time > last)
break; //该情况不需要找朋友,直接办就行了,因为没有等待时间
if(temp.name != People[i].name && !visited[i] && Friends.count(temp.name) && Friends.count(People[i].name) && Friends[temp.name] == Friends[People[i].name])
{
//如果对于一个人有朋友的话,就可以随着朋友直接输出
visited[i] = true;
printf("%s\n",People[i].name);
result += last - People[i].Start_Time; //同上,一个人他前面的最后一个人办完需要的时间 - 这个人来的时间 = 他要等待的时间
last += People[i].End_Time; //同上,更新办完当前业务需要的时间 (加上来这个人办业务需要的时间)
}
}
}
}
printf("%1f\n",1.0*result/N);
return 0;
}