电梯控制算法(6)多电梯场景——两个等价电梯——静态指派

电梯控制算法 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;
}

 

运行示例:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值