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的更多相关文章
随机推荐
- bzoj3168 钙铁锌硒维生素 (矩阵求逆+二分图最小字典序匹配)
设第一套为A,第二套为B 先对于每个B[i]判断他能否替代A[j],即B[i]与其他的A线性无关 设$B[i]=\sum\limits_{k}{c[k]*A[k]}$,那么只要看c[j]是否等于零即可 ...
- HAOI2018苹果树
题解 首先所有生成树的情况树是\(n!\)的,因为第一次有1中方法,第二次有两种放法,以此类推... 然后我们发现距离这种东西可以直接枚举每条边算贡献. 于是我们枚举了一个点\(i\),又枚举了这个点 ...
- 【WebSocket】WebSocket介绍
1.背景 在WebSocket出现之前客户端向服务器发出请求是通过http协议实现的,而http协议有个特点是通行请求只能由客户端发起,然后服务端响应查询结果,HTTP 协议没法让服务器主动向客户端推 ...
- nginx 配置详解(转)
nginx概述 nginx是一款自由的.开源的.高性能的HTTP服务器和反向代理服务器:同时也是一个IMAP.POP3.SMTP代理服务器:nginx可以作为一个HTTP服务器进行网站的发布处理,另外 ...
- (转)spring异常抛出触发事务回滚策略
背景:在面试时候问到事务方法在调用过程中出现异常,是否会传递的问题,平时接触的比较少,有些懵逼. spring异常抛出触发事务回滚策略 Spring.EJB的声明式事务默认情况下都是在抛出unchec ...
- laravel 读写分离源码解析
前言:上一篇我们说了<laravel 配置MySQL读写分离>,这次我们说下,laravel的底层代码是怎样实现读写分离的. 一.实现原理 说明: 1.根据 database.php ...
- showdoc app接口文档编写利器
通过朋友介绍,才知道有这么好的一个在线接口编写文档开源项目,非常感谢原作者的贡献 ShowDoc介绍 关于ShowDoc的介绍,请访问:http://blog.star7th.com/2015/11/ ...
- SNMP mib文件说明
MIB file的开始和结束 所有的MIB file的都以DEFINITIONS ::= BEGIN关键字开始,以END结束.我们所有添加的节点均应在此之间. XXX-TEST-MIB DEFINIT ...
- unionFS学习笔记
AUFS基础http://coolshell.cn/articles/17061.html DOCKER对于AUFS文件系统的应用http://www.cnblogs.com/ilinuxer/p/6 ...
- VMware Workstation 常见问题解决
本文以FAQ的方式进行整理,大家可以根据关键字进行查找即可. 问题一:VMware 安装64位操作系统报错“此主机支持Intel VT-x, 但Intel VT-x处于禁用状态” 问题二:This v ...