In the comments on CB, the OP response comments: "the requests are static, at the beginning I get a complete list." I would welcome counter examples and / or other reviews, since it seems to me that if we are given all the trips in advance, the problem can be dramatically reduced if we consider the following:
Since the elevator has unlimited bandwidth, any trips going up this end are lower than the highest floor that we will visit are not related to our calculations. Since we guarantee the transfer of all these pickups and exits on the way to the highest point, we can put them on our schedule after considering the top-down trips.
Any trips “contained” in other trips in one direction are also irrelevant, since we will transfer these pickups and departures during the “most external” trips and can be accordingly planned after consideration.
Any overlapping downstream trips can be combined for some reason, which will soon become apparent.
Any downward trips occur either before or after reaching the highest point (except that the top floor has reached the pickup). The optimal schedule for all downstream trips that we have defined in order to happen to the highest point (considering only the types of “external container” and two or more overlapping trips as one trip), one after the other, when we go up as we are on the way anyway.
How to determine which downstream trips should occur after the highest point?
We carry out our calculation on one point, TOP . Let me name a trip that includes the top floor reached by H and the top floor reached HFR . If HFR is a pickup, H decreases and TOP = H_dropoff . If HFR is dropoff, H increases and TOP = HFR .
The lowering trips that must be planned after the top floor is visited are members of the largest group of neighboring downstream trips (considering only the types of “external containers” and two or more overlapping trips as one trip) that we can collect, starting from the next lower descending departure after TOP and continuing down, where their combined individual distances double, more than the total distance from TOP to their last fall. That is, where (D1 + D2 + D3...+ Dn) * 2 > TOP - Dn_dropoff
Here's a rude attempt at 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 ab = 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(\ab -> compare ba) 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 (\ab -> compare ba) 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
Output:
*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]