buaaoo_second_improvement
你不优化,我不优化,那大家就都是满分啦
(一)写在最前
电梯问题由于和实际关联比较紧密,所以实际上可以操作的空间比较多。
但第二单元的电梯,需要实现捎带;第三单元的电梯,需要实现楼层限制、人数限制、三电梯,限制了可以优化的范围,所以这里仅仅做一些自己在写电梯时候的小思考。
(二)第二次电梯
经过查阅资料,可以得知比较常见的电梯调度算法包括FCFS、SSTF、SCAN等,其中比较容易书写,且可以保证性能不是很差的是SCAN电梯。但是查阅资料可以发现,SCAN电梯是需要反复扫描楼层,来检测是否有人员可以搭乘电梯,这就带来了一个问题,可能刚刚经过的楼层恰好来了个请求,且运动方向上并没有新的请求,原始的SCAN电梯会选择 一条道跑到黑,这里是有一些可以改进的空间的。
可以通过判断当前电梯运动方向上是否有新的请求在等待,如果没有,则折返(这里在书写的时候容易把代码写成带有上下优先级的做法,导致电梯反复运动,所以这里放上我的代码)
private void detect() {
if (arr.isEmpty()) {
upordown = 0;
}
if (upordown == 0 || upordown == 1) {
for (Person p : arr) {
if (p.getfrom() > nowfloor &&
p.getstatus() == 0 && passanger < max) {
upordown = 1;
break;
} else if (p.getto() > nowfloor && p.getstatus() == 1) {
upordown = 1;
break;
} else {
upordown = 0;
}
}
}
if (upordown == 0 || upordown == -1) {
for (Person p : arr) {
if (p.getfrom() < nowfloor &&
p.getstatus() == 0 && passanger < max) {
upordown = -1;
break;
} else if (p.getto() < nowfloor && p.getstatus() == 1) {
upordown = -1;
break;
} else {
upordown = 0;
}
}
}
}
这段代码通过一个标记位来检测电梯是否需要折返,1代表上行,0代表停止,-1代表下行。之前说过的有上下优先级是因为在判断条件中未加入当前运行方向的判断。至此,SCAN电梯就进化成了所谓的LOOK电梯。
事实上,通过检测电梯当前楼层上下分别有多少请求,可以通过请求的数量来判断向哪一方向运动更优,这里仅需要设立两个数量记录位即可,为了保证可能到来的新请求对判断造成影响,上下方向请求数量若小于某个临界值,则并不需要改变电梯运动方向,以此来做优化。
看到某位神仙通过写了好几个电梯同时跑,然后输出一个buffer存的字符串数组,也是觉得十分神奇了,不过,用了一些数据测试这位大神的电梯,与我写的这个单LOOK电梯(优化后),并没有发现他的方法有明显的优势,有的点我比他慢,有的点他比我慢,不过可能是因为测试数据数量比较少,这里仅作记录,膜拜一下多电梯大佬。
(三)第三次电梯
由于第二次电梯不限载客数量,不需要考虑换乘等,所以导致需要优化的点其实很少,所以这里重点讨论一下第三次电梯。
第三次电梯有三个限制,一是人数限制,二是楼层限制,三是三个电梯。这里仅对人数限制和楼层限制做讨论。
人数限制导致了之前缩写的LOOK优化电梯在捎带的时候性能并不是很好,而最简单的调度器使用是通过直接分发到ABC三个电梯中,让电梯去运送用户,这里就导致了优先级的产生,会让某个电梯负载过重,而在请求队列中阻塞许多用户,而另外两个电梯甚至可能没有请求,这里可以通过对每个请求使用if去判断,是否可以通过电梯直达,若可以,则记录可以的电梯数目,通过一个随机数对此数目取余得到放请求的电梯,这样随机分布对于第三次强测中纯随机数据很有效,实现也很简单,这里不再赘述。
之后是楼层限制,这一点拖慢电梯的主要原因是换乘,我们需要通过选择某个电梯将乘客请求送到某个楼层,再由另外的电梯去运送,而每个电梯的运送速度是不一样的,所以在考虑分发乘客请求的时候,我对时间片进行了考量,代码如下:
int[] flag = {0, 0, 0, 0, 0, 0};
double[] min = {200, 200, 200, 200, 200, 200};
int [] n = {1, 1, 1, 1, 1, 1};
int i;
double t = 200;
int j = 0;
if (change == 1) {
if (elevator1[this.from + 3] == 1 && elevator2[this.to + 3] == 1) {
flag[0] = 1;
}
else if (elevator1[this.to + 3] == 1 && elevator2[this.from + 3] == 1) {
flag[1] = 1;
}
else if (elevator1[this.from + 3] == 1 && elevator3[this.to + 3] == 1) {
flag[2] = 1;
}
else if (elevator1[this.to + 3] == 1 && elevator3[this.from + 3] == 1) {
flag[3] = 1;
}
else if (elevator3[this.from + 3] == 1 && elevator2[this.to + 3] == 1) {
flag[4] = 1;
}
else if (elevator3[this.to + 3] == 1 && elevator2[this.from + 3] == 1) {
flag[5] = 1;
}
for (i = 0; i < 24; i++){
if ((Math.abs(i - 3 - this.from) * 0.4 + Math.abs(i - 3 - this.to) * 0.6 < min[2]) && ac[i] == 1) {
min[2] = Math.abs(i - 3 - this.from) * 0.4 + Math.abs(i - 3 - this.to) * 0.6;
n[2] = i - 3;
}
if ((Math.abs(i - 3 - this.to) * 0.4 + Math.abs(i - 3 - this.from) * 0.6 < min[3]) && ac[i] == 1) {
min[3] = Math.abs(i - 3 - this.to) * 0.4 + Math.abs(i - 3 - this.from) * 0.6;
n[3] = i - 3;
}
if ((Math.abs(i - 3 - this.from) * 0.4 + Math.abs(i - 3 - this.to) * 0.5 < min[0]) && ab[i] == 1) {
min[0] = Math.abs(i - 3 - this.from) * 0.4 + Math.abs(i - 3 - this.to) * 0.5;
n[0] = i - 3;
}
if ((Math.abs(i - 3 - this.to) * 0.4 + Math.abs(i - 3 - this.from) * 0.5 < min[1]) && ab[i] == 1) {
min[1] = Math.abs(i - 3 - this.to) * 0.4 + Math.abs(i - 3 - this.from) * 0.5;
n[1] = i - 3;
}
if ((Math.abs(i - 3 - this.from) * 0.5 + Math.abs(i - 3 - this.to) * 0.6 < min[4]) && bc[i] == 1) {
min[4] = Math.abs(i - 3 - this.from) * 0.5 + Math.abs(i - 3 - this.to) * 0.6;
n[4] = i - 3;
}
if ((Math.abs(i - 3 - this.to) * 0.5 + Math.abs(i - 3 - this.from) * 0.6 < min[5]) && bc[i] == 1) {
min[5] = Math.abs(i - 3 - this.to) * 0.5 + Math.abs(i - 3 - this.from) * 0.6;
n[5] = i - 3;
}
}
for (i = 0; i < 6; i++) {
if (flag[i] != 1) {
min[i] = 200;
}
} for (i = 0; i < 6; i++) {
if (t > min[i]) {
t = min[i];
j = i;
}
}
this.to = n[j];
}
大致思路是记录电梯两两重叠的楼层,之后可以把乘客通过from和to与ABC电梯组合,分成六种情况,通过考量乘客在某种组合下所需要运动的总时间来决定拆分请求应该放在哪个电梯中,以此来求得比较优化的换乘方式,而非直接无脑将乘客送到1楼或者15楼,留下电梯日门。
事实上,由于电梯换乘的开关门时间比较大,如果乘客能够直达,便最好不需要换乘。当然,这里由于电梯运动的因素,还可以考量三电梯换乘,不过这里需要记录电梯当前乘客数,运动方向,请求队列长度等来让电梯进行“预知未来”,由于本人太菜,没有完全实现这一部分,就不做讨论了。
我说自己菜,大佬说自己菜.jpg
buaaoo_second_improvement的更多相关文章
随机推荐
- Wiki leaks files backup
Wiki leaks files backup 来源 http://ftp.icm.edu.pl/packages/incoming/torrent/ Index of /packages/inco ...
- 简单 php 代码跟踪调试实现
简单 php 代码跟踪调试实现 debug_backtrace:生成回溯 debug_print_backtrace:打印回溯 1. debug_backtrace ($options = DEBUG ...
- 修改linux下yum镜像源为国内镜像
修改为163yum源-mirrors.163.com 1.首先备份系统自带yum源配置文件/etc/yum.repos.d/CentOS-Base.repo [root@localhost ~]# m ...
- java的集合:List、Set和Map
虚线是接口,实线是实现类: 集合能够解决的问题:集合可以丽杰为是一种更高级的数组,可以保存多条数据 本质:java官方开发人员基于java的一些基础内容(数组等等)创建了一些接口和类,然后使用这些接口 ...
- Django web编程3 -- 创建用户账户
我们将建立一个用户注册和身份验证系统,让用户能够注册账户,进而登录和注销.我们将创建一个新的应用程序,其中包含与处理用户账户相关的所有功能.我们还将对模型Topic 稍做修改,让每个主题都归属于特定用 ...
- k8s网络之设计与实现
k8s网络主题系列: 一.k8s网络之设计与实现 二.k8s网络之Flannel网络 三.k8s网络之Calico网络 K8s网络设计与实现是在学习k8s网络过程中总结的内容.在学习k8s网络各种插件 ...
- Windows 10中Oracle数据库导出到Access数据库(MDB)
本篇博文简单介绍将Oracle数据库中表导出到Access数据库(主要是MDB格式)的方法.主要有三种,分别是PL/SQL.ESFDatabaseMigrationToolkit及ODBC. PL/S ...
- JAVA开发环境搭建(Mac)
1. 打开Terminal, 执行命令: java -version 即可查看到我们所安装的jdk版本. 2.安装jdk成功之后,我们还需要配置jdk环境变量. 使用命令: /usr/libexec/ ...
- AE二次开发中几个功能速成归纳(符号设计器、创建要素、图形编辑、属性表编辑、缓冲区分析)
/* * 实习课上讲进阶功能所用文档,因为赶时间从网上抄抄改改,凑合能用,记录一下以备个人后用. * * ----------------------------------------------- ...
- 01.QT初学--两个窗口相互切换
//qqwidget.cpp #include "qqwidget.h" #include "ui_qqwidget.h" qqwidget::qqwidget ...