银行排队问题之单队列多窗口服务
这是以前写的一道题,题目记不清了,是PTA上的,所以题干应该都差不多,思路都在注释里了
#include <iostream>
using namespace std;
#define MAXSIZE 2000
typedef struct {
int P;
int T;
}people;
typedef struct {
int time;
int num;
int finishtime;
}window;
typedef struct {
people* base;
int front;
int rear;
}Queue;
void InitQueue(Queue& Q) {
Q.base = (people*)malloc(MAXSIZE * sizeof(people));
if (!Q.base) exit(0);
Q.front = Q.rear = 0;
}
void EnQueue(Queue& Q, people p) {
if ((Q.rear + 1) % MAXSIZE == Q.front)
exit(0);
Q.base[Q.rear] = p;
Q.rear = (Q.rear + 1) % MAXSIZE;
}
void DeQueue(Queue& Q, people& p) {
if (Q.front == Q.rear)
exit(0);
p = Q.base[Q.front];
Q.front = (Q.front + 1) % MAXSIZE;
}
int main()
{
Queue Q;
people p;
window windows[10];
InitQueue(Q);
int N, K, sum = 0, P, T, pro, maxlen = 0, finaltime = 0;
cin >> N;
for (int i = 0; i < N; i++) {
cin >> T;
cin >> P;
if (P > 60)
P = 60;
p.P = P;
p.T = T;
EnQueue(Q, p); //将每一位客户入队
}
cin >> K;
if (N == 0) {
printf("%.1f", 0.0);
cout << " " << 0 << " " << 0 << endl;
for (int i = 0; i < K - 1; i++)
cout << 0 << " ";
cout << 0;
exit(0);
}
for (int i = 0; i < K; i++) { //将所有窗口的等待时间和办理人数置为0
windows[i].num = 0;//窗口的办理人数
windows[i].time = 0;//窗口的排队时间
windows[i].finishtime = 0;//窗口的完成时间
}
//理解窗口的完成时间:这是一个累加量,举个例子来说明,比如由事先的计算可知,二号窗口今一天需要服务的客户数量为3,那么该窗口的
//完成时间就是最后一个客户业务办理完成后的时间,如果第二个客户服务完后,第三个客户还没来,那个这个等待新客户的时间也要算进完
//成时间内。当然,事先是不知道各个窗口分别要服务多少人的,所以,当所有客户中的最后一个客户进入某个窗口后,各个窗口的完成时间
//才为各个窗口的最终完成时间,否则需要一直累加。
//思路:
//每个新客户出队之后,先计算各个窗口需要的等待时间,每个窗口对于他来说的等待时间都为前一个客户的等待时间减去两者的到来时间差。
//若等待时间为负数(比如有三个窗口,第二个客户来的时候,第二三个窗口的等待时间对他来说是负数),则置为零。
//再判断哪些窗口的等待时间为0,若有,则去该窗口,同时该窗口的等待时间要变为该客户的业务办理时间,该窗口的完成时间要变为该客户
//的到达时间+业务办理时间,然后退出循环,下一个客户出队。若所有窗口的等待时间都大于零,即需要排队,则比较各个窗口的等待时间,
//找出等待时间最少的窗口,新客户就去这个窗口(同时计算排队时间的累加器要加上这个排队时间),然后这个窗口的等待时间就变为原等待
//时间+新客户的业务办理时间,该窗口的完成时间为原完成时间+新客户的业务办理时间(不用再加上新客户的到达时间,这是与不需排队的
//情况的完成时间计算不同的地方)
pro = 0; //pro用来记录上一位顾客的到达时间
for (int i = 0; i < N; i++) {
DeQueue(Q, p);
for (int j = 0; j < K; j++) { //计算各个窗口的等待时间
if (windows[j].time > 0) {
windows[j].time -= (p.T - pro);//每个窗口的等待时间为前一个客户的等待时间减去两者的到来时间差
if (windows[j].time < 0) //如果某个窗口的等待时间小于0,则置为0
windows[j].time = 0;
}
}
pro = p.T;
int j = 0;
for (j = 0; j < K; j++) { //如果有窗口不需要排队
if (windows[j].time == 0) {
windows[j].time += p.P;
windows[j].num++;
windows[j].finishtime = p.T + p.P; //若该窗口不需等待,则该窗口完成时间为新客户到达时间加上新客户办理业务时间
if (windows[j].finishtime > finaltime)
finaltime = windows[j].finishtime;
break;
}
}
if (j == K) //j==K说明上一个for循环没有中途break,窗口都需要排队
{
int min = 0;
for (int k = 1; k < K; k++) { //找到需要排队时间最短的窗口
if (windows[k].time < windows[min].time)
min = k;
}
sum += windows[min].time; //排队时间总数增加
windows[min].finishtime += p.P; //若该窗口需要等待,则该窗口的完成时间为前一个客户的完成时间加上新客户的办理时间
if (windows[min].finishtime > finaltime)
finaltime = windows[min].finishtime;
if (windows[min].time > maxlen)
maxlen = windows[min].time;
windows[min].time += p.P; //该窗口的排队时间增加
windows[min].num++;
}
}
double aver = (double)sum / N;
printf("%.1f", aver);
cout << " " << maxlen << " " << finaltime << endl;
for (int i = 0; i < K - 1; i++)
cout << windows[i].num << " ";
cout << windows[K - 1].num;
getchar();
getchar();
return 0;
}