SharedSchoolSpace/可供参考资料_zyx/银行排队问题.cpp

272 lines
6.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//问题2-2
#include <iostream>
#include <ctime>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
using namespace std;
#define Status int
#define OVERFLOW 2
#define ERROR 1
#define OK 0;
typedef int QElemType;
int queue_number[10] = { 0 };//queue_number记录队列人数
int i, j = 0;//i用于客户计数j用于窗口计数
int no = 0;//no用于记录客户序号其中第一位客户的序号为1
int time_length = 0;//time_length记录模拟程序运行时长
int window_number = 0;
typedef struct QNode
{
int no;//序号
double amount;//总金额
double remain_amount;//未取金额(不计当前轮)
struct QNode* next;
}QNode, * QueuePtr;
typedef struct
{
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}LinkQueue;
Status InitQueue(LinkQueue& Q)
{
Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
if (!Q.front) exit(OVERFLOW);
Q.front->next = NULL;
return OK;
}
Status DestroyQueue(LinkQueue& Q)
{
while (Q.front)
{
Q.rear = Q.front->next;
free(Q.front);
Q.front = Q.rear;
}
return OK;
}
Status QueueEmpty(LinkQueue Q)
{
return (Q.front == Q.rear);
}
Status GetHead(LinkQueue Q, int& e1, double& e2, double& e3)
{
if (Q.front == Q.rear) return ERROR;
e1 = Q.front->next->no;
e2 = Q.front->next->amount;
e3 = Q.front->next->remain_amount;
return OK;
}
Status EnQueue(LinkQueue& Q, int& e1, double& e2, double& e3)
{
QueuePtr p;
p = (QueuePtr)malloc(sizeof(QNode));
if (!p) exit(OVERFLOW);
p->no = e1;
p->amount = e2;
p->remain_amount = e3;
p->next = NULL;
Q.rear->next = p;
Q.rear = p;
return OK;
}
Status DeQueue(LinkQueue& Q, int& e1, double& e2, double& e3)
{
if (Q.front == Q.rear) return ERROR;
QueuePtr p;
p = Q.front->next;
e1 = p->no;
e2 = p->amount;
e3 = p->remain_amount;
Q.front->next = p->next;
if (Q.rear == p) Q.rear = Q.front;
delete p;
return OK;
}
int MinQueue()
{
int s = 10000, k = 0, temp;
for (k = 0;k < window_number;k++)
{
if (queue_number[k] < s)
{
temp = k;
s = queue_number[k];
}
}
return temp;
}
int MaxQueue()
{
int s = -1, k = 0, temp;
for (k = 0;k < window_number;k++)
{
if (queue_number[k] > s)
{
temp = k;
s = queue_number[k];
}
}
return temp;
}
void Remove(LinkQueue& Q)//检查第一个人是否已取完。注意判断队列是否为空。
{
if (!QueueEmpty(Q))
{
if (Q.front->next->remain_amount <= 1e-8)
{
int e1 = -1;
double e2 = -1, e3 = -1;
DeQueue(Q, e1, e2, e3);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
FOREGROUND_INTENSITY | FOREGROUND_GREEN);//设置绿色
cout << "" << (double)i / 10 + 0.1 << "秒时" << j + 1 << "号窗口"
<< "" << e1 << "位客户完成业务,取走共" << e2 << "万元。" << endl;
queue_number[j]--;
}
}
}
void Join(LinkQueue* q)
{
int a = rand() % 60;
//a的值在0-60之间随机分布只有当a=0到window_number-1时才产生新客户
//平均每6秒产生window_number个客户与窗口数量对应
if (a < window_number)
{
no++;
double b = double(rand() % 191) / 10 + 1;//b的值在1-20之间随机分布(精度0.1),代表用户取钱的金额数(单位:万元)
int m = MinQueue();
EnQueue(q[m], no, b, b);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN);//设置红色和绿色相加
cout << "" << (double)i / 10 + 0.1 << "秒时第" << no << "位客户进入窗口"
<< m + 1 << "队列,需取" << b << "万元。" << endl;
queue_number[m]++;
}
}
void ChangeQuene(LinkQueue* q)
{
int min = MinQueue(), max = MaxQueue();
while (queue_number[max] - queue_number[min] >= 2)
{
int e1;
double e2, e3;
DeQueue(q[max], e1, e2, e3);
EnQueue(q[min], e1, e2, e3);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
FOREGROUND_INTENSITY | FOREGROUND_BLUE);//设置蓝色
cout << "" << e1 << "位客户从窗口" << max + 1 << "队列调整到窗口" << min + 1 << "队列" << endl;
queue_number[min]++;
queue_number[max]--;
min = MinQueue();
max = MaxQueue();
}
}
void Withdraw(LinkQueue& Q)
{
if (!QueueEmpty(Q) && i != time_length)
{
Q.front->next->remain_amount -= 0.2;//每0.1秒取走0.2万
}
}
void Undone(LinkQueue& Q)
{
while (!QueueEmpty(Q))
{
int e1 = -1;
double e2 = -1, e3 = -1;
DeQueue(Q, e1, e2, e3);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE);//设置绿色和蓝色相加
cout << "窗口" << j + 1 << "队列第" << e1 <<
"位客户未完成业务,未取共" << e2 << "万元。" << endl;
}
}
int main()
{
cout << "请输入模拟程序运行时长单位1-300之间的整数" << endl;
//time_length = 120;
cin >> time_length;
while (time_length <= 0 || time_length > 300)
{
cout << "您输入的时间不符合要求,请重新输入:";
cin >> time_length;
}
cout << "请输入银行窗口数1-10之间的整数" << endl;
cin >> window_number;
while (window_number <= 0 || window_number > 10)
{
cout << "您输入的窗口数不符合要求,请重新输入:";
cin >> window_number;
}
LinkQueue* q = (LinkQueue*)malloc(window_number * sizeof(LinkQueue));
//队列初始化
for (j = 0;j < window_number;j++)
{
InitQueue(q[j]);
}
srand(time(nullptr));//设置随机数种子
//核心代码
for (i = 0;i <= time_length * 10;i++)//每0.1秒循环一次,直到到达预定时间
{
//先检查第一个人是否已取完。注意判断队列是否为空
for (j = 0;j < window_number;j++)
{
Remove(q[j]);
}
//再把新客户加到人最少的队伍
Join(q);
//再判定是否有客户需要重新选择队列
ChangeQuene(q);
//再给当前队伍第一位取钱,注意判断队列是否为空
//注意i=time_length时取钱业务已经停止
for (j = 0;j < window_number;j++)
{
Withdraw(q[j]);
}
Sleep(93);
//100单位为毫秒即0.1秒。考虑到程序运行时间将100改为93
//由于Sleep()函数的精度不高,因此循环间隔不能太小
}
//程序结束前,输出未取完钱的人的情况
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
FOREGROUND_INTENSITY);//设置颜色,没有添加颜色,故为原色
cout << endl << "取钱业务结束。" << endl << endl;
for (j = 0;j < window_number;j++)
{
Undone(q[j]);
}
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
FOREGROUND_INTENSITY);//设置颜色,没有添加颜色,故为原色
return 0;
}