电梯控制算法 https://blog.csdn.net/nameofcsdn/article/details/106874615
对于多电梯场景,首先我们考虑最简单的情况,即两个电梯是等价的,都是全部楼层可达的。
当有乘客在外面按电梯时,哪个电梯去响应呢?
应该是根据电梯的实时运行状况,判断哪个电梯去接乘客比较快,就派哪个电梯去。
这里分两种指派电梯的情况,一种是在外部输入时立即决定派哪部电梯去响应(静态指派),另一种是一直实时计算哪个电梯更快就派哪个(动态指派)。
其实应该还有一种,直接指派两个电梯都响应,当一部电梯到达后,另外一部电梯才停止响应,这种应该比较少见,因为消耗太大,而且对于整体效率而言不见得好。
本文讨论静态指派,即在外部输入时立即决定派哪部电梯去响应。
在选择的时候,需要计算电梯到请求楼层的逻辑距离,即电梯可能先往反方向运动,送完乘客之后再回来接客。
不考虑限层策略,也不考虑停靠楼层较多对电梯的影响,只考虑逻辑上一共隔了多少楼层。
注意,如果外部输入是3,即既有上行又有下行,那么可能需要两部电梯分别响应上行和下行。
也就是说,这种情况需要分开成2个单独的事务进行处理。
要计算逻辑距离,就需要知道电梯的当前位置,当前运动方向。
当前运动方向分为上行、下行、空闲(即静止)三种,是否空闲根据进出电梯最大楼层和最小楼层进行判断。
代码:
#include<iostream>
#include<windows.h>
#include <thread>
#include<time.h>
#include<math.h>
using namespace std;
#define LEVEL 16
int flag[2][LEVEL + 1]; //1到Level层的外部输入,取值为0,1,2,3,其中0表示无乘客,1表示有乘客上行,2表示有乘客下行,3表示既有上行又有下行
int dest[2][LEVEL + 1]; //目的楼层的记录,取值为0,1,其中0表示不是目的地,1表示是目的地
int levelMax[2], levelMin[2]; //levelMax是进出电梯最大楼层,levelMin是进出电梯最小楼层
int loc[2]; //当前楼层
int direc[2]; //当前运动方向,=1表示上行,=2表示下行,=0表示空闲
void upPull(int loc, int id)//上行接客
{
flag[id][loc]--;
if (id)cout << " ";
cout << "电梯" << id << "上行接客" << loc << endl;
}
void downPull(int loc, int id)//下行接客
{
flag[id][loc] -= 2;
if (id)cout << " ";
cout << "电梯" << id << "下行接客" << loc << endl;
}
void push(int loc, int id)//送客
{
dest[id][loc] = 0;
if (id)cout << " ";
cout << "电梯" << id << "送客" << loc << endl;
}
int getMax(int id)//进出电梯最大楼层
{
levelMax[id] = 0;
for (int loc = 1; loc <= LEVEL; loc++)
{
if (flag[id][loc] || dest[id][loc])levelMax[id] = max(levelMax[id], loc);
}
return levelMax[id];
}
int getMin(int id)//进出电梯最小楼层
{
levelMin[id] = LEVEL + 1;
for (int loc = 1; loc <= LEVEL; loc++)
{
if (flag[id][loc] || dest[id][loc])levelMin[id] = min(levelMin[id], loc);
}
return levelMin[id];
}
int length(int lev, int fla, int id)
{
int dir = direc[id], loca = loc[id];
if (dir == 1) {
if (fla == 1) {
if (loca < lev)return lev - loca;
return abs(getMax(id) - loca) + abs(getMax(id) - getMin(id)) + abs(lev - getMin(id));
}
return abs(getMax(id) - loca) + abs(getMax(id) - min(getMin(id), lev));
}
if (dir == 2) {
if (fla == 2) {
if (loca > lev)return loca - lev;
return abs(loca - getMin(id)) + abs(getMax(id) - getMin(id)) + abs(getMax(id) - lev);
}
return abs(loca - getMin(id)) + abs(max(getMax(id), lev) - getMin(id));
}
return abs(lev - loca);
}
int select(int lev, int fla)//fla=1,2,仅上行或者仅下行
{
if (length(lev, fla, 0) < length(lev, fla, 1))return 0;
return 1;
}
void input2(int lev, int fla) //fla=1,2,仅上行或者仅下行
{
int id = select(lev, fla);
flag[id][lev] |= fla;
}
void input()//输入电梯id、楼层和标志,标志1-3是外部输入上下行,其他标志是内部输入目标楼层
{
int lev, fla;
while (cin >> lev >> fla) if (lev > 0 && lev <= LEVEL)
{
if (fla == 1 || fla == 2) {
input2(lev, fla);
}
else if (fla == 3) {
input2(lev, 1);
input2(lev, 2);
}
else {
int id; //id是电梯编号,只有内部输入才有id,取值0或1
cin >> id;
dest[id][lev] = 1;//内部输入
}
}
}
void run(int id)//电梯运行主控逻辑
{
if (id)cout << " ";
cout << "电梯" << id << " 当前楼层" << loc[id] << endl;
while (1)
{
if (getMax(id) < getMin(id))direc[id] = 0;
while (loc[id] <= getMax(id))
{
direc[id] = 1;
if (flag[id][loc[id]] & 1)upPull(loc[id], id);
if (dest[id][loc[id]])push(loc[id], id);
Sleep(1000);
if (loc[id] < getMax(id))loc[id]++;
else break;
if (id)cout << " ";
cout << "电梯" << id << " 当前楼层" << loc[id] << endl;
}
while (loc[id] >= getMin(id))
{
direc[id] = 2;
if (flag[id][loc[id]] & 2)downPull(loc[id], id);
if (dest[id][loc[id]])push(loc[id], id);
Sleep(1000);
if (loc[id] > getMin(id))loc[id]--;
else break;
if (id)cout << " ";
cout << "电梯" << id << " 当前楼层" << loc[id] << endl;
}
}
}
void run1()
{
run(0);
}
void run2()
{
run(1);
}
int main()
{
thread t1(input);
thread t2(run1);
Sleep(500);
thread t3(run2);
t1.join();
t2.join();
t3.join();
return 0;
}
运行示例: