题目如下:
代码:
#include <stdio.h>
#include <stdlib.h>
#define MaxWindow 3 //定义最多有的窗口数
#define MaxProc 60 //定义最长事务处理时间
typedef struct People ElementType;
struct People /*顾客类型*/
{
int T; //顾客到达时间
int P; // 顾客事务被处理时间
};
typedef int Position;
struct QNode /*队列节点*/
{
ElementType * Data; //顾客数组
Position Front,Rear; //队列的头、尾 指针
int MaxSize; //队列的最大容量
};
typedef struct QNode * Queue;
Queue CreateQueue(int MaxSize){ /*创建队列 Q 以及赋值*/
Queue Q = (Queue)malloc(sizeof(struct QNode));
Q->Data = (ElementType*)malloc(MaxSize*sizeof(ElementType));
Q->Front = 0 ;
Q->Rear = 0 ;
Q->MaxSize = MaxSize ;
return Q;
}
bool IsFull(Queue Q){ /*判断队列 Q 是否为满*/
return (Q->Rear+1) % Q->MaxSize == Q->Front ;
}
bool AddQ( Queue Q , ElementType X ){ /*将元素 X 压入队列*/
if(!IsFull(Q)){
Q->Rear = (Q->Rear+1) % Q->MaxSize ;
Q->Data[Q->Rear] = X ;
return true ;
}
}
bool IsEmpty(Queue Q){ /*判断队列 Q 是否为空*/
return (Q->Front == Q->Rear);
}
ElementType DeleteQ(Queue Q){ /*队列出列*/
if(!IsEmpty(Q)){
Q->Front = (Q->Front+1) % Q->MaxSize ;
return Q->Data[Q->Front] ;
}
}
int FindNextWindow(int W[],int K,int *WaitTime,int *Long) /*给定 K个窗口,返回下一个空闲窗口的位置 以及在相邻两次窗口空闲之间所等待的时间 WaitTime 和窗口最长的事务处理时间*/
{
int WinAvail ; //下一个窗口的位置
int MinW = MaxProc+1 ; //最短事务处理时间,初始化为超过最大值
int i ;
int MaxTime=0;
for(i=0;i<K;i++) //扫描每个窗口,找到最短事务处理时间
if(W[i] < MinW)
{
MinW = W[i];
WinAvail = i;
}
*WaitTime = MinW ; //最短事务处理时间 就是两次空窗间的 等待时间
for(int j=0;j<K;j++) //扫描每个窗口,找到最长事务处理时间
{ if(W[j] > MaxTime)
MaxTime = W[j];
}
*Long=MaxTime; //最长的事务处理时间,用来求最后的完成时间
for( i=0; i<K ; i++ ) /*刷新所有窗口的事务处理状态*/
W[i] -= MinW;
return WinAvail ; //返回下一个窗口的位置
}
int FindMaxWaitTime(int A[],int N){ //用来寻找 MaxWaitTime[] 中最长的等待时间并返回
int MaxTime = 0;
for(int i=0;i<N;i++)
if(A[i] > MaxTime)
MaxTime = A[i];
return MaxTime;
}
int FindLongTime(int Window[],int K,int CurrentTime)
{
int LongTime = 0;
for(int i=0;i<K;i++)
if(Window[i] > LongTime)
LongTime = Window[i];
LongTime += CurrentTime;
return LongTime;
}
void QueueingAtBank(Queue Q,int N) /*根据顾客队列 Q 和人数 N ,返回顾客的平均等待时间、最长等待时间、最后完成时间、各窗口服务的人数*/
{
struct People Next; //下一位顾客
int K; //营业窗口个数
int i,j;
/*---初始化----------------------------------------------*/
int TotalTime=0; //全体成员总的等待时间 /
int CurrentTime=0; //当前时间,开门营业时间为 0
int Window[MaxWindow]={0}; //营业窗口需要处理事务的时间长度
int WaitTime=0; //相邻两次窗口空闲之间所等待的时间
int WinAvail=0; //空闲时间窗口的位置
int LongTime=0; //最后完成时间
int Long=0; //记录 FindNextWindow() K个窗口中最长处理事务时间
int MaxN=0; //顾客序号
int MaxWaitTime[N]={0}; //用来存放每个顾客的 最长等待时间
int Sum[MaxWindow]={0}; //用来统计每个窗口各服务了多少人
scanf("%d",&K); //读入营业窗口个数
if(K>MaxWindow) //当输入的窗口数大于规定的大窗口数时,按规定的最大的窗口数算
K=MaxWindow;
while( !IsEmpty(Q) )
{
/*---第一步: 处理掉当前最短的事务,得到下一个空闲窗口*/
WinAvail = FindNextWindow( Window , K , &WaitTime , &Long); //用来寻找 WaiTime 和更新 CurrentTime
CurrentTime += WaitTime; //当前时间=上一次处理完事务的当前时间+这次处理完事务的时间
/*---第二步:下一位顾客出列*/
Next = DeleteQ(Q);
if(CurrentTime >= Next.T) //如果顾客已经到达等待
{
int G=TotalTime; //TotalTme = 在顾客 Q 前的全部顾客的等待时间
TotalTime += (CurrentTime-Next.T); //TotalTime = 在顾客 Q 前的全部顾客的等待时间 + 当前顾客 Q 本身的等待时间
MaxWaitTime[MaxN] = TotalTime-G; //所以 MaxWaitTime[MaxN] = 当前顾客 Q 本身的等待时间
MaxN++;
}
else{ //顾客不需要等待
WaitTime=Next.T-CurrentTime; //空闲窗口等待顾客的时间
for(j=0;j<K; j++){ //空闲窗口在等待顾客的同时其他窗口也在办理业务,所以需要重新刷新所有窗口至顾客到达的时间 ,此时当前时间就是顾客到达的时间
Window[j]-=WaitTime;
if(Window[j]<0)
Window[j]=0;
}
CurrentTime=Next.T; //更新当前时间为顾客到达时间
}
/*----第三步:顾客 Next 到 WinAvail 窗口接受服务*/
WinAvail = FindNextWindow( Window , K , &WaitTime , &Long); //当上述 else 条件成立时,它会重新刷新所有窗口至顾客到达的时间,此时空闲窗口在等待顾客的同时其他窗口也在办理业务,所以存在一种可能,就是在第一次找到的窗口前面还会有空闲的窗口,所以需要重新刷新让其找到合适的位置
Sum[WinAvail]=Sum[WinAvail]+1; //统计每个窗口的服务人数
if(Next.P>MaxProc) //当顾客的事务处理时间 P 大于窗口的最长服务时间时,按窗口最长服务时间算
Next.P=MaxProc;
Window[WinAvail]=Next.P;
}
WinAvail = FindNextWindow( Window , K , &WaitTime , &Long);
int Longtime=CurrentTime+Long;
printf("%.1lf %d %d\n",(double)TotalTime/(double)N,FindMaxWaitTime(MaxWaitTime,MaxN),Longtime); //打印时间
for(int A=0;A<K;A++){ //打印窗口服务顾客数且行末不能有空格
if(A==K-1)
printf("%d",Sum[A]);
else
printf("%d ",Sum[A]);
}
}
void DestroyQueue(Queue &Q) /*销毁队列*/
{
free(Q);
}
int main()
{
int N; //顾客总数
Queue Q; //顾客队列
int i;
ElementType X; //一个顾客结构体类型
scanf("%d",&N); //读入顾客人数
Q=CreateQueue(N+1); //建立空的顾客队列
for(i=0;i<N;i++){ //顾客依次入列
scanf("%d%d",&X.T,&X.P);
AddQ(Q,X);
}
QueueingAtBank(Q,N); // 输出
DestroyQueue(Q); //销毁队列
return 0;
}
/*
输入:
9
0 20
1 15
1 60
2 10
10 5
10 3
30 18
31 25
31 2
3
注:
平均等待时间 = TotalTime 除以 顾客人数
最长等待时间 ,将各个顾客的等待时间存进一个数组 MaxWaitTime[] 中 , 调用函数 FindMaxWaitTime(int A[],int N) ,求出最长的等待时间
最后完成时间 = 目前时间CurrenTime + 最大的顾客等待时间
各个窗口服务人数 = 返回的WinAvail , 表示第 WinAvail 窗口这里来了一个顾客,用一个数组 Sum[] 来记录
*/