你不优化,我不优化,那大家就都是满分啦
(一)写在最前
电梯问题由于和实际关联比较紧密,所以实际上可以操作的空间比较多。
但第二单元的电梯,需要实现捎带;第三单元的电梯,需要实现楼层限制、人数限制、三电梯,限制了可以优化的范围,所以这里仅仅做一些自己在写电梯时候的小思考。
(二)第二次电梯
经过查阅资料,可以得知比较常见的电梯调度算法包括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