我有一个单层电梯的建筑物,我需要找到这个电梯的算法。我们得到了这种形式的对象列表:{i->j}
,其中i
是居民想要乘坐电梯的楼层,j
是他想要下楼的楼层。
无数人可以同时使用电梯,与人们待在电梯里的时间无关。电梯从一楼开始。
我在网上查了一下,然后找到了电梯算法"但它并没有真正帮助我。它说我应该一路向上,然后一路向下。但考虑一个居民想要从1到100,而另一个居民想要从50到49.使用上述算法,它将需要151层的距离。如果我改为遵循这条路径:1-> 50-> 49-> 100,它只需要102层,这样更好。
我应该使用什么算法?
答案 0 :(得分:2)
这是将此问题表述为基于时间的整数计划的一种方法。 (生成所有约束似乎有点过分,但保证能够产生最佳解决方案)
假设电梯需要1个单位时间才能从楼层F
转到F+1
或F-1
。
洞察力:我们使用的事实是t
在任何时候都只有一个决定。是上升还是下降。这就是我们问题的决策变量。如果电梯在时间t向上移动,则DIR_t = +1,否则为-1。
我们希望尽量减少所有乘客到达目的地的时间。
此表格更清晰
Time FLOOR_t Dir_t
1 1 1
2 2 1
3 3 1
4 4 1
... ... ...
49 49 1
50 50 -1
51 49 1
52 50 1
...
100 99 1
101 100 NA
现在,让我们带上乘客。有P个乘客,每个人都想去
SF
到EF
(他们的起始楼层到他们的结束楼层,他们的目的地。)
因此,我们会为每位乘客(SF_p, EF_p)
提供p
。
我们知道在时间t电梯所在的楼层是
F_t = F_t-1 + DIR_t-1
(F0 = 0,DIR_0 = 1,F1 = 1只是为了开始关闭。)
现在,让ST_p
成为乘客开始电梯旅程的时刻。让ET_p
成为乘客p结束电梯旅程的时刻。
请注意,SF
和EF
是输入参数,但ST
和ET
是变量, IP将在解决时设置。也就是说,地板是给我们的,我们必须提出时代。
ST_p = t if F_t = SF_p # whenever the elevator comes to a passenger's starting floor, their journey starts.
ET_p = t if F_t = EF_p AND ST_p > 0 (a passenger cannot end their journey before it commenced.)
This can be enforced by introducing new 0/1 indicator variables.
ETp > STp # you can only get off after you got on
最后,让我们介绍一个数字T
,这是整个行程完成的时间。它是每个p的所有ET的最大值。这是需要最小化的。
T > ET_p for all p # we want to find the time when the last passenger gets off.
全部放在一起:
Min T
T > ET_p for all p
F_t = F_t-1 + DIR_t-1
ETp > STp # you can only get off after you got on
ST_p = t if F_t = SF_p # whenever the elevator some to a passenger's starting floor, their journey starts.
ET_p = t if F_t = EF_p AND ST_p > 0
ET_p >= 1 #everyone should end their journey. Otherwise model will give 0 as the obj function value.
DIR_t = (+1, -1) # can be enforced with 2 binary variables if needed.
现在解决了这个IP问题后,可以使用每个DIR_t
的每个t
的值来跟踪确切的行程。
答案 1 :(得分:1)
这是一个多项式时间动态程序,其运行时间不依赖于楼层数。如果我们贪婪地接载乘客并让他们等待,那么相关的状态是电梯已经到达的楼层间隔(因此乘客被接走),电梯最近拾取或下降的楼层,以及两个可选的价值:为了使目前内部的乘客下降而有义务访问的最低楼层,并且最高。所有这种状态都可以通过五名乘客的身份加上恒定的比特数来描述。
我很确定这里还有改进的余地。
答案 2 :(得分:0)
您的问题反映了磁头调度算法。
结帐shortest seek time first vs scan, cscan, etc。
有些情况下sstf获胜,但如果它是50到10,你也有2到100,3到100,4到100,5到100,6到100等。你可以看到你添加对所有其他人开销。此外,如果传入请求的查找时间较短,则可能会发生starvation(类似于进程调度)。
在您的情况下,它实际上取决于请求是静态还是动态。如果您想最小化方差,请使用scan / cscan等。
答案 3 :(得分:0)
在对C.B。的回答中,OP评论:"请求是静态的。在一开始我得到完整的清单。"我欢迎反例和/或其他反馈,因为在我看来,如果我们提前给所有旅行,如果我们考虑以下因素,问题可以大大减少:
由于电梯的容量无限制,因此任何高于我们将访问的最高楼层的行程都与我们的计算无关。由于我们保证在前往最高点的路上通过所有这些接送和下降,我们可以在考虑下行之后将它们放入我们的时间表中。
任何旅行包含'在同一方向的其他旅行也是无关紧要的,因为我们将在“最外面的”期间通过这些接送和下降。旅行后,可以在考虑之后适当安排。
任何重叠的下行旅行可能会合并,原因很快就会显现出来。
任何下降行程都会在达到最高点之前或之后发生(不包括最高楼层到达拾取)。我们确定在最高点之前发生的所有下行行程的最佳时间表(仅考虑外部容器类型和两次或多次重叠行程作为一次行程)是一个接一个因为我们提升了,因为无论如何我们都在上升。
我们如何确定在最高点之后应该发生哪些下行旅程?
我们参考一个点TOP
进行计算。我们将此行程称为最高楼层达到H
且最高楼层达到HFR
。如果HFR
是取件,则H
正在降序且TOP = H_dropoff
。如果HFR
为下降,H
正在提升且TOP = HFR
。
在要访问的最高楼层之后应安排的下行行程是最大的相邻下行行程的所有成员(仅考虑外部容器类型和两个或更多重叠行程作为一个我们可以收集,从TOP
之后的下一个下降行程开始并继续向下,其中它们的组合个体距离加倍,大于从TOP
到最后一次下降的总距离。也就是说,(D1 + D2 + D3...+ Dn) * 2 > TOP - Dn_dropoff
这是Haskell的一次粗暴尝试:
import Data.List (sort,sortBy)
trips = [(101,100),(50,49),(25,19),(99,97),(95,93),(30,20),(35,70),(28,25)]
isDescending (a,a') = a > a'
areDescending a b = isDescending a && isDescending b
isContained aa@(a,a') bb@(b,b') = areDescending aa bb && a < b && a' > b'
extends aa@(a,a') bb@(b,b') = areDescending aa bb && a <= b && a > b' && a' < b'
max' aa@(a,a') bb@(b,b') = if (maximum [b,a,a'] == b) || (maximum [b',a,a'] == b')
then bb
else aa
(outerDescents,innerDescents,ascents,topTrip) = foldr f ([],[],[],(0,0)) trips where
f trip (outerDescents,innerDescents,ascents,topTrip) = g outerDescents trip ([],innerDescents,ascents,topTrip) where
g [] trip (outerDescents,innerDescents,ascents,topTrip) = (trip:outerDescents,innerDescents,ascents,max' trip topTrip)
g (descent:descents) trip (outerDescents,innerDescents,ascents,topTrip)
| not (isDescending trip) = (outerDescents ++ (descent:descents),innerDescents,trip:ascents,max' trip topTrip)
| isContained trip descent = (outerDescents ++ (descent:descents),trip:innerDescents,ascents,topTrip)
| isContained descent trip = (trip:outerDescents ++ descents,descent:innerDescents,ascents,max' trip topTrip)
| extends trip descent = ((d,t'):outerDescents ++ descents,(t,d'):innerDescents,ascents,max' topTrip (d,t'))
| extends descent trip = ((t,d'):outerDescents ++ descents,(d,t'):innerDescents,ascents,max' topTrip (t,d'))
| otherwise = g descents trip (descent:outerDescents,innerDescents,ascents,topTrip)
where (t,t') = trip
(d,d') = descent
top = snd topTrip
scheduleFirst descents = (sum $ map (\(from,to) -> 2 * (from - to)) descents)
> top - (snd . last) descents
(descentsScheduledFirst,descentsScheduledAfterTop) =
(descentsScheduledFirst,descentsScheduledAfterTop) where
descentsScheduledAfterTop = (\x -> if not (null x) then head x else [])
. take 1 . filter scheduleFirst
$ foldl (\accum num -> take num sorted : accum) [] [1..length sorted]
sorted = sortBy(\a b -> compare b a) outerDescents
descentsScheduledFirst = if null descentsScheduledAfterTop
then sorted
else drop (length descentsScheduledAfterTop) sorted
scheduled = ((>>= \(a,b) -> [a,b]) $ sort descentsScheduledFirst)
++ (if isDescending topTrip then [] else [top])
++ ((>>= \(a,b) -> [a,b]) $ sortBy (\a b -> compare b a) descentsScheduledAfterTop)
place _ [] _ _ = error "topTrip was not calculated."
place floor' (floor:floors) prev (accum,numStops)
| floor' == prev || floor' == floor = (accum ++ [prev] ++ (floor:floors),numStops)
| prev == floor = place floor' floors floor (accum,numStops)
| prev < floor = f
| prev > floor = g
where f | floor' > prev && floor' < floor = (accum ++ [prev] ++ (floor':floor:floors),numStops)
| otherwise = place floor' floors floor (accum ++ [prev],numStops + 1)
g | floor' < prev && floor' > floor = (accum ++ [prev] ++ (floor':floor:floors),numStops)
| otherwise = place floor' floors floor (accum ++ [prev],numStops + 1)
schedule trip@(from,to) floors = take num floors' ++ fst placeTo
where placeFrom@(floors',num) = place from floors 1 ([],1)
trimmed = drop num floors'
placeTo = place to (tail trimmed) (head trimmed) ([],1)
solution = foldl (\trips trip -> schedule trip trips) scheduled (innerDescents ++ ascents)
main = do print trips
print solution
输出:
*Main> main
[(101,100),(50,49),(25,19),(99,97),(95,93),(30,20),(35,70),(28,25)]
[1,25,28,30,25,20,19,35,50,49,70,101,100,99,97,95,93]