| You are to direct a lift system in a building with N floors, M lifts, and a capacity of C people per lift. The simulation runs for four days. When individuals wish to make a journey between floors, they press a button at their starting floor indicating the direction (up or down) in which they wish to travel. When they enter the lift, they press a button in the lift indicating which floor they wish to travel to. Your task is to schedule the lifts to minimize the time spent travelling by the occupants of the building.
Time is split up into ticks, periods of length 3 seconds. In each tick, the following events occur.
- New journeys are created. If the button indicating their direction of travel on their starting floor is unlit, they press it. They then join the back of the queue on that floor. Anyone who has been queueing for at least twenty minutes gives up and takes the stairs.
- You are given the list of newly pressed buttons, from people starting journeys this tick, and from people who ended up entering lifts in the previous tick. You then tell the lifts what to do this tick.
- The lifts move, open/close their doors, or stay still. If the lift's doors are open, a light above the lift indicate which direction it is travelling in. People enter the lift if it is going in their chosen direction of travel. People who have arrived at their destination also exit the lift. If a lift with open doors has no entries or exits in that tick, it closes its doors at the end of the tick.
- On entering the lift, people press buttons, indicating which floor to go to.
You must supply two methods. At the start of each of the four days initialise is passed the arguments N,M,and C. It is then the case that every tick your method step is called and passed parameters upRequests, downRequests, liftRequests, and state. upRequests and downRequests contain lists of any floors at which buttons have been pressed in this tick desiring to go up or down. LiftRequests and destinationRequests show which buttons in lifts have been pressed; in particular, liftRequests[x] is the index of the lift in which the button is pressed, and destinationRequests[x] is the destination requested. state is a string of characters representing the state of each lift.
Each lift can be in one of five states: U (travelling upwards), D (travelling downwards), S(stationary, with doors closed), L(loading, having claimed to be about to be going up), M(loading, having claimed to be about to be going down). If moving, lifts travel one floor per tick. You may not change the state of a lift that is loading in either direction (the doors will close automatically when loading is finished, changing the state to 'S'). With the one exception of 'U' to 'D' and vice versa, all other state transitions are allowed. step must return a String ans of states, where ans[i] represents the new state for lift i.
Buttons are lit when pressed; when a lit button is pressed you are not informed. Floor buttons become unlit when that floor is arrived at by a lift claiming to be going in that direction, and lift buttons are unlit when the lift arrives at the requested floor. Floor buttons are then relit if individuals still wish to go in a particular direction, and no lifts are currently loading at that floor to go in that direction. Individuals having a choice of getting on multiple lifts will always choose the lift in the lowest numbered shaft. Lifts all start the day at floor zero. The simulation runs from 7a.m. to 8p.m. No journeys are generated after 7p.m.
Test Generation
Test cases are generated by choosing integers N in [5,40], M in [10,50], C in [5,30], P in [25,200], B in [1,20], and a double businessprob in [0,1].
The test cases are generated to simulate a building with some retail floors and some business floors. The business floors have about P employees per floor, while the retail floors have about P/10 per floor. Each employee arrives in the morning and leaves in the afternoon, and takes about one break per ten hours where they go down to the bottom floor. Shoppers come and go from the retail floors at a rate of about P per floor per hour, with fewer people early in the morning and late in the afternoon. The shoppers also move between retail floors with about P/2 of them leaving each floor for some other floor per hour. Finally, there is some random traffic, at a rate of about B people leaving each floor for some other floor per hour. Some more details of the test generation are below. For the precise implementation, see the source code.
Each non-ground floor is denoted business with probability businessprob, and retail otherwise. totretail is then the total number of retail floors. Then arrtimes, deptimes, arrdevs, depdevs, are generated, each of size N (with integer elements). Elements of arrtimes are randomly generated in [1200,3600] (8a.m. to 10a.m.), deptimes in [10800,13200](4p.m. to 6p.m.), and arrdevs and depdevs in [100,600](5-30 minutes). In expectation, each business floor has about P employees and retail floors have about P/10 employees. The employees of a floor have (roughly) Gaussian arrival times with means from arrtimes and deviations from arrdevs. Similarly for their departure times. We can calculate exp_{i,t}, the expected fraction of staff present on floor i at time t (this peaks at close to 1 for the whole of the middle period of the day). The staff on each floor take breaks at a rate of about 1/10 per hour. Thus, about exp_{i,t}*P/10 people leave each business floor for the ground level each hour (and a similar number return), while 1/10 as many leave and return each retail floor.
At time t, shoppers arrive and travel to floor i and leave floor i at a rate that is proportional to exp_{i,t}, peaking at P people per hour during the middle part of the day when exp_{i,t}=1. In addition, shoppers move between retail floors. At peak traffic, about P/2 people leave each retail floor for some other (randomly chosen) retail floor per hour. Thus, if there are R retail floors, the retail traffic from one to another peaks at P/2/(R-1). The i->j traffic is multiplied by exp_{i,t} and exp_{j,t}, reducing it early in the morning and late in the afternoon.
Finally, there is some random traffic between every pair of floors, at a rate of B/N people for each pair of floors per hour.
Scoring
Your preliminary score for a test case is the sum of the squares of the times (in ticks) of all journeys taken. If someone gives up and takes the stairs, that journey is scored as if it had taken 60 minutes. Anyone still in the system at 8p.m. shall be scored as if they had finished their journey at 8p.m.. The benchmark score is the sum over all journeys of (d+3)^{2}, where d is the distance between the departure and arrival floors. Your final score for the test case is equal to sqrt((preliminary score+1)/number of journeys)-sqrt(benchmark score/number of journeys). In the event that your program crashes, exceeds the time limit or returns invalid output, your score for that case is zero. Your final score is the sum over all test cases where you have a non-zero score of BEST/YOUR where BEST is the least non-zero score for that test-case, and YOUR is your score for that case.
Visualization
A tool is available at http://www.topcoder.com/contest/problem/LiftScheduler/vis.html. |