模拟银行实现VIP服务

模拟银行
请根据以下代码实现以下功能。
https://pan.baidu.com/s/1pv2ajyhWu4w94s2LEawM3w?pwd=kct0
提取码:kct0
1.VIP窗口
在原有代码基础上添加VIP窗口功能,VIP窗口的出纳员只服务VIP用户,当VIP用户到达后可以
在本窗口按照到达先后顺序等待。
一、
约定1号出纳员所在的1号窗口为VIP窗口,且银行中只有一个VIP窗口。
约定普通用户只能在普通窗口排队等候,其选择窗口的优先级为:空普通窗口>非空普通窗口。
约定用户排队过程中选定窗口后就会一直在该队列中等待,不会更换排队队伍。
约定用户之间无法感知对方是处理何种业务,不知道其业务所需的具体时间和剩余时间。
约定模拟时间外不产生用户到达事件,但是银行将会处理完所有用户到达事件。
第一问约定
约定VIP用户可以在普通窗口和VIP窗口排队等候,其选择窗口的优先级为:空VIP窗口>空普通窗口>非空VIP窗口>非空普通窗口。
将在去掉到达时间与服务时间随机化的情况下,对代码进行正确性验证。验证内容是增设VIP窗口对服务情况产生的影响。
请按照如下提示修改代码:

// event.h
enum isVip {notVip, Vip};
struct event
{
...
isVip isvip;
...
};
// event.h
InitEvent(...)
CompareEvent(...)
// ...
...
以所示输入为例,时间处于048时分别到达一名随机身份的顾客,银行将安排窗口为顾客服务。对于8时到来的VIP用户,他所面临的的情况:在增设VIP窗口前,不区分顾客身份服务,8时到来的顾客面对两个非空串口的情况下将会选择随机选择一个窗口进行服务,VIP身份没有获得收益;在增设VIP窗口后,VIP用户在某些情况下可以比普通用户更快受到服务。
```c++
# 用例1
# ./bank
Enter the simulation time in minutes: 10
Enter the number of bank tellers: 2
Enter the range of arrival times in minutes: 4 4
Enter the range of service times in minutes: 9 9

(繁忙程度=实际服务时间/总服务时间):
到达队列情况 总用时 1号窗口繁忙程度 2号窗口繁忙程度
P、P、V(增设VIP窗口前)
P、P、V(增设VIP窗口后)
二、约定VIP用户可以在VIP窗口排队等候,或者在普通窗口队列中插队(即排到普通窗口队列最前
面)。
约定插队的VIP用户在普通窗口中按照到达顺序先后进行排队。
约定VIP用户选择窗口的优先级为:空VIP窗口>空普通窗口>插队到普通窗口队列。
请编程实现功能
2.VIP限时等待
约定只有出纳员服务完当前用户后,才会重新计算所有排队的用户中的VIP用户的等待时间,如果等待时间已到达最长等待时间,将优先服务等待时间长的VIP用户。
约定等待时间满的VIP顾客,可以更换柜台服务。即所有柜台出纳员会按照等待时间由长到短的顺序服务所有队列中的VIP用户。(对于VIP用户而言,打破最初不能更换队伍的约定)无VIP窗口情况下,银行规定,VIP用户等待时间不得超过X分钟,VIP用户与普通用户之间设置排队策略。
修改代码,使得VIP用户最多等待waitHigh时间。注意:出纳员只需要照顾本队列中的VIP用户。

printf("Enter the longest waitting time the customer can tolerate in minutes: ");
scanf("%d", &s->waitHigh);

3.最佳排队机制
如何决定三种等待时间的重要性?如何赋予不同的权重?如何在不同的权重设置下实现适宜的排队机制?请根据实验数据进行情况讨论。
综合考虑各类角色等待时间:被VIP插队的用户越多,普通用户越不满;VIP等待的时间越长,VIP越不满;有人排队但有窗口闲置时,银行不满。
请通过实验数据说明如何设置排队机制可能是最优的。
https://pan.baidu.com/s/1pv2ajyhWu4w94s2LEawM3w?pwd=kct0
提取码:kct0

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
这是一道比较复杂的模拟题,需要对代码逐步进行修改和补全。以下是具体实现步骤:

第一问:

1.首先,在event.h文件中添加isVip枚举类型,并在event结构体中添加isvip成员变量。

2.在InitEvent函数中,添加对isvip的初始化。

3.在CompareEvent函数中,首先比较两个事件的发生时间eventTime,若相同则比较窗口号win,若仍然相同则比较身份isvip(VIP用户优先)。

4.在BankSimulator.cpp文件中,修改ServiceNext函数,在处理到达队列非空的情况下,添加对VIP窗口的判断。若当前是VIP用户且VIP窗口空闲,则直接进入VIP窗口服务,否则按照原来的规则选择窗口。

5.在main函数中,根据需要添加VIP用户的到达事件即可。

第二问:

1.在customer.h文件中,添加waitTime成员变量,表示该顾客等待的时间(单位为分钟)。

2.在BankSimulator.cpp文件中,为所有顾客的waitTime初始化为0。

3.在ServiceNext函数中,修改顾客服务完毕后的处理。首先判断是否有VIP顾客在等待,若有,则按照等待时间排序,选取等待时间最长的VIP顾客进行服务;若没有,则按照普通顾客队列的规则进行服务。

4.在AddEvent函数中,若当前添加的是VIP用户,且最长等待时间waitHigh已经到达,则将其添加到普通用户队列的队首,表示该VIP用户插队到普通用户队列中。

5.在main函数中,根据需要添加VIP用户,并根据waitHigh设定最长等待时间。

第三问:

1.最佳排队机制旨在平衡所有用户的等待时间,需要综合考虑各种情况影响因素,并赋予不同的权重。如考虑用户感受的不满程度不同,可以为等待时间设置不同的惩罚系数;如考虑银行的服务效率,可以为空闲窗口设置奖励;如考虑VIP用户的特殊需求,可以为VIP用户设置特殊待遇等。通过不同的权重设置,可以在不同的情况下实现适宜的排队机制。

2.具体实现可以将用户感受的不满程度与实际等待时间挂钩,设定某种函数关系。如可以定义每分钟的等待时间对用户感受的等待程度产生1单位的贡献,再根据顾客身份、窗口闲忙程度等情况进行加权。

3.根据实验数据可以进行情况讨论,如可以分别考虑以下情况:

  • 在不考虑VIP用户时,不同窗口的平均繁忙程度如何?窗口间的繁忙程度是否平衡?是否存在一些窗口无人排队的情况?

  • 在加入VIP用户因素后,普通用户的等待时间与VIP用户的等待时间如何?VIP用户是否有更多的服务机会?VIP用户因插队而产生的不满度如何?

  • 在考虑VIP用户最长等待时间的情况下,如何设置合适的等待时间阈值?可否通过实验数据找出最优解?
    如果我的回答解决了您的问题,请采纳!

该回答引用ChatGPT
1. 实现 VIP 窗口功能
增设一个 isvip 属性,将 VIP 用户和普通用户区分开。在银行类中新增一个 VIP 窗口,并定义VIP顾客选择窗口的优先级:
空 VIP 窗口 > 空普通窗口 > 非空 VIP 窗口 > 非空普通窗口。即 VIP 顾客优先选择 VIP 窗口,其次选择普通窗口,最后选择已有顾客的 VIP 窗口和普通窗口。

上述更改后的部分代码如下:

c++
// event.h

enum isVip {notVip, Vip};

struct event
{
int time;
int id;
int st;
int queueId;
int queueNum;
isVip isvip;
int eventTypeId;
};

void InitEvent(eventType *EventList, stateType *State);

int CompareEvent(const void * a, const void * b);

stateType *EventRun(eventType *EventList, stateType *State, int TotalTime);

// bank.cpp

class Bank{
private:
// 两个窗口,第一个窗口为 VIP 窗口
Queue *Line1, *Line2;
Server *Serve1, *Serve2;
int currTime; // 当前时间
int totalTime; // 总时间
int numTeller;
int arrivalMin, arrivalMax, serviceMin, serviceMax;
int waitHigh; // VIP 最大等待时间
int cntAdd; // 已经到达的顾客数量
int cntServed; // 已经服务的顾客数量
double avgWaitTime; // 普通顾客平均等待时间
double avgSpendTime; // 普通顾客平均服务时间
double vipWaitTime; // VIP 顾客总等待时间
double vipSpendTime; // VIP 顾客总服务时间

public:
Bank(){
Line1 = new Queue();
Line2 = new Queue();
Serve1 = new Server();
Serve2 = new Server();
currTime = 0;
numTeller = 1;
waitHigh = 5;
cntAdd = 0;
cntServed = 0;
avgWaitTime = 0;
avgSpendTime = 0;
vipWaitTime = 0;
vipSpendTime = 0;
}

~Bank(){
delete Line1;
delete Line2;
delete Serve1;
delete Serve2;
}

void initBank(int time, int n, int a, int b, int c, int d){
totalTime = time;
numTeller = n;
arrivalMin = a;
arrivalMax = b;
serviceMin = c;
serviceMax = d;
}

void addCustomer(){

// 随机生成新顾客的到达时间和服务时间
cntAdd++;
int arriveTime = currTime + randInt(arrivalMin, arrivalMax);
int serveTime = randInt(serviceMin, serviceMax);
isVip isvip = notVip;
if (randInt(0, 14) < 1){
isvip = Vip;
}

// 添加事件
event tmp;
tmp.time = arriveTime;
tmp.id = cntAdd;
tmp.st = serveTime;
tmp.eventTypeId = arrive;
tmp.isvip = isvip;

// 选择队列
if (tmp.isvip == Vip) {
if (Serve1->isBusy() && Serve2->isBusy()) {
// 两个窗口都有顾客
// 选择两个队伍中排队人数少的队伍
if (Line1->getSize() <= Line2->getSize()){
tmp.queueId = 1;
Line1->enQueue(new Customer(tmp.id, tmp.st, currTime - arriveTime, isvip));
tmp.queueNum = Line1->getSize();
} else {
tmp.queueId = 2;
Line2->enQueue(new Customer(tmp.id, tmp.st, currTime - arriveTime, isvip));
tmp.queueNum = Line2->getSize();
}
} else if (Serve1->isBusy()){
// 窗口1有顾客,窗口2空闲
// 选择窗口2服务
tmp.queueId = 2;
Line2->enQueue(new Customer(tmp.id, tmp.st, currTime - arriveTime, isvip));
tmp.queueNum = Line2->getSize();
} else {
// 窗口1空闲,选择窗口1服务
tmp.queueId = 1;
Line1->enQueue(new Customer(tmp.id, tmp.st, currTime - arriveTime, isvip));
tmp.queueNum = Line1->getSize();
}
} else {
if (Serve1->isBusy() && Serve2->isBusy()){
// 两个窗口都有顾客
// 选择两个队伍中排队人数少的队伍
if (Line1->getSize() <= Line2->getSize()){
tmp.queueId = 1;
Line1->enQueue(new Customer(tmp.id, tmp.st, currTime - arriveTime, isvip));
tmp.queueNum = Line1->getSize();
} else {
tmp.queueId = 2;
Line2->enQueue(new Customer(tmp.id, tmp.st, currTime - arriveTime, isvip));
tmp.queueNum = Line2->getSize();
}
} else if (Serve1->isBusy()){
// 窗口1有顾客,窗口2空闲
// 选择窗口2服务
tmp.queueId = 2;
Line2->enQueue(new Customer(tmp.id, tmp.st, currTime - arriveTime, isvip));
tmp.queueNum = Line2->getSize();
} else {
// 窗口1空闲,选择窗口1服务
tmp.queueId = 1;
Line1->enQueue(new Customer(tmp.id, tmp.st, currTime - arriveTime, isvip));
tmp.queueNum = Line1->getSize();
}
}
eventType *e = new eventType;
e->eventStruct = tmp;
AddEvent(e);
}

void serveCustomer(){

// 窗口1接待顾客
if (Serve1->isBusy()){
Serve1->decreaseRemainTime();
if (Serve1->getRemainTime() == 0){
// 窗口1服务结束
Customer *served = Serve1->getCustomer();
cntServed++;

// VIP 顾客重新选择队伍
if (served->getIsVIP() == Vip) {
served->updateWaitTime(currTime);
if (served->getWaitTime() < waitHigh) {
if (Line1->getSize() == 0) {
Serve1->setCustomer(served);
Serve1->increaseRemainTime(served->getServeTime());
} else if (Line2->getSize() == 0) {
Serve2->setCustomer(served);
Serve2->increaseRemainTime(served->getServeTime());
} else if (Line1->getFront()->getData()->getIsVIP() == Vip) {
Serve1->setCustomer(served);
Serve1->increaseRemainTime(served->getServeTime());
} else {
Serve2->setCustomer(served);
Serve2->increaseRemainTime(served->getServeTime());
}
}
else {
vipWaitTime += served->getWaitTime();
vipSpendTime += served->getServeTime();
auto vipQueue = new Queue();
while(!Line1->isEmpty() && Line1->getFront()->getData()->getID() != served->getID()) {
vipQueue->enQueue(Line1->deQueue());
}
if (!Line1->isEmpty()) {
Line1->deQueue();
}
while(!Line1->isEmpty()) {
vipQueue->enQueue(Line1->deQueue());
}
while(!Line2->isEmpty() && Line2->getFront()->getData()->getID() != served->getID()) {
vipQueue->enQueue(Line2->deQueue());
}
if (!Line2->isEmpty()) {
Line2->deQueue();
}
while(!Line2->isEmpty()) {
vipQueue->enQueue(Line2->deQueue());
}
vipQueue->enQueue(served);
while(!vipQueue->isEmpty()) {
auto front = vipQueue->deQueue();
if (Serve1->isBusy() && Serve1->getCustomer()->getID() == served->getID()) {
Serve1->removeCustomer();
}
if (front->getIsVIP() == Vip) {
Line1->enQueue(front);
} else {
Line2->enQueue(front);
}
}
Serve1->setCustomer(nullptr);
Serve2->setCustomer(nullptr);
}
} else {
auto front = new Customer();
if (Line1->getSize() > 0 && Line2->getSize() > 0) {
if (Serve1->getRemainTime() <= Serve2->getRemainTime()) {
front = Line1->deQueue();
} else {
front = Line2->deQueue();
}
} else if (Line1->getSize() > 0){
front = Line1->deQueue();
} else if (Line2->getSize() > 0){
front = Line2->deQueue();
}
front->updateWaitTime(currTime);
avgWaitTime += front->getWaitTime();
avgSpendTime += front->getServeTime();
auto s = new Server();
s->setCustomer(front);
s->increaseRemainTime(front->getServeTime());
if (Serve1->isBusy()){
Serve2 = s;
} else {
Serve1 = s;
}
}
}
} else {
// 窗口1有空闲
if (Line1->getSize() > 0) {
Customer *front = Line1->deQueue();