電梯【難度:5級】:
答案1:
class Dinglemouse(object):
def __init__(self, queues, capacity):
self.inLift, self.moves = [], [0]
self.peopleOnFloorsLists = [ list(floor) for floor in queues ]
self.stage, self.moving = -1, 1
self.capacity = capacity
def theLift(self):
while self.areStillPeopleToBeLifted() or not self.liftIsEmpty():
self.stage += self.moving
if self.areSomePeopleIn_WannaGoOut() or self.areSomeGuysWaitingSameWay_AtThatFloor(self.stage):
self.liftStopAtThisStage()
self.somePeopleIn_GoOut()
self.takeIn_AllPeopleGoingTheSameWay()
""" Decide what the lift has to do now:
No change of direction in these cases :
- If the lift contains people going in the same direction: They have the priority...
- If there are people further that want to go in the same direction...
- If the lift is Empty and that some people further want to go in the other direction,
the lift goes as far as it can before taking in some people again (who wana go to
in the other direction).
In other cases, the lift begins to move the other way.
For the simplicity of the implementation, the lift is shifted one step backward, so it
will be able to managed the presence of people at the current floor (before update) who
want to go in the other direction.
"""
if not ( self.anyPeopleIn_GoingSameWay() \
or self.areSomeGuysFurther_Wanting_(self.areSomeGuysWaitingSameWay_AtThatFloor) \
or (self.liftIsEmpty() and self.areSomeGuysFurther_Wanting_(self.areSomeGuysWaitingOtherWay_AtThatFloor) )):
self.moving *= -1
self.stage -= self.moving
self.liftStopAtThatStage(0) # return to the ground if needed
return self.moves
def areStillPeopleToBeLifted(self): return any( bool(queue) for queue in self.peopleOnFloorsLists )
def liftIsEmpty(self): return not self.inLift
def areSomePeopleIn_WannaGoOut(self): return self.stage in self.inLift
def somePeopleIn_GoOut(self): self.inLift = list( filter(lambda i: i != self.stage, self.inLift) )
def anyPeopleIn_GoingSameWay(self): return any( guy * self.moving > self.stage * self.moving for guy in self.inLift)
def areSomeGuysWaitingSameWay_AtThatFloor(self, lvl): return any( i * self.moving > lvl * self.moving for i in self.peopleOnFloorsLists[lvl] )
def areSomeGuysWaitingOtherWay_AtThatFloor(self, lvl): return any( i * self.moving < lvl * self.moving for i in self.peopleOnFloorsLists[lvl] )
def liftStopAtThisStage(self): self.liftStopAtThatStage(self.stage)
def liftStopAtThatStage(self, lvl):
if self.moves[-1] != lvl: self.moves.append(lvl)
def takeIn_AllPeopleGoingTheSameWay(self):
peopleGoingIn, peopleThere = [], self.peopleOnFloorsLists[self.stage]
for i in peopleThere: # Get all people who can enter the lift, according to its capacity and the queue order
if len(peopleGoingIn) + len(self.inLift) == self.capacity: break
if i * self.moving > self.stage * self.moving: peopleGoingIn.append(i)
self.inLift += peopleGoingIn # update the lift content
while peopleGoingIn: peopleThere.remove(peopleGoingIn.pop()) # Remove the new people in the lift from this floor (using mutability of list, passed by reference)
def areSomeGuysFurther_Wanting_(self, func):
i = self.stage + self.moving
while 0 <= i < len(self.peopleOnFloorsLists):
if func(i): return True
i += self.moving
return False
答案2:
class Dinglemouse(object):
def __init__(self, queues, capacity):
self.Q = {k:[[p for p in q if (p > i if k == 'U' else p < i)][::-1] for i, q in enumerate(queues)] for k in 'UD'}
self.floors = [f for f in range(len(queues))]
self.capacity = capacity
def theLift(self):
f, d, lift, path = 0, 'U', [], [0]
while sum(len(q) for q in self.Q['U']) + sum(len(q) for q in self.Q['D']) + len(lift) > 0:
if self.Q[d][f] or f in lift:
if path[-1] != f: path.append(f)
lift = [p for p in lift if p != f]
while len(lift) < self.capacity and self.Q[d][f]: lift.append(self.Q[d][f].pop())
f += {'U':1, 'D':-1}[d]
if f not in self.floors:
d = {'U':'D', 'D':'U'}[d]
f += {'U':1, 'D':-1}[d]
return path if path[-1] == 0 else path + [0]
答案3:
class Dinglemouse(object):
def __init__(self, queues, capacity):
self.queues, self.capacity = queues, capacity
def theLift(self):
double = len(self.queues) * 2
status = [[] for _ in range(double)]
for floor, queue in enumerate(self.queues):
for request in queue:
if request < floor:
status[~floor] += [double - request - 1]
else:
status[ floor] += [request]
liftcar = []
stops = [0]
floor = 0
while liftcar + sum(status, []):
if floor in liftcar or status[floor]:
liftcar = [person for person in liftcar if person != floor]
vacant = self.capacity - len(liftcar)
liftcar += status[floor][:vacant]
status[floor] = status[floor][vacant:]
stops += [floor if floor < double // 2 else double - floor - 1]
floor = (floor + 1) % double
return [0] + [b for a, b in zip(stops, stops[1:] + [0]) if a != b]
答案4:
import operator
class Dinglemouse(object):
"""Class to control elevator."""
DIR_FUNC = {1: operator.gt, 0: operator.lt}
def __init__(self, people, capacity):
"""Init function."""
self.capacity = capacity
self.occupants = []
self.history = [0]
self.floor = 0
self.direction = 1 # 1 is up, 0 is down.
self.queues = list(people)
self.stops = set()
def theLift(self): # pylint: disable=C0103
"""Start the lift."""
while self.check_for_waiting(): # while anyone is waiting
self.build_stops() # Add people waiting to go current dir to stops
while self.stops: # Continue until no stops remain
self.stop(self.get_next_stop()) # Stop at next stop
self.change_direction() # Change direction when stops is empty
self.update_floor(0) # Done. Got to the bottom floor.
return self.history
def check_for_waiting(self):
"""Check to see if anyone is waiting."""
for floor in self.queues:
if floor:
return True
return False
def change_direction(self):
"""Change direction."""
self.direction = int(not self.direction)
def unload(self):
"""Unload passengers."""
self.occupants = [x for x in self.occupants if x != self.floor]
def load(self):
"""Load passengers."""
temp_list = []
for person in self.queues[self.floor]:
if (len(self.occupants) < self.capacity # If there is room
# and someone going the direction of the lift.
and self.DIR_FUNC[self.direction](person, self.floor)):
self.occupants.append(person)
self.stops.add(person)
else:
temp_list.append(person) # Save remaining people to leave
self.queues[self.floor] = temp_list # Replace orig list with remaining
def stop(self, floor):
"""Stop on floor."""
self.update_floor(floor)
self.unload()
self.load()
def update_floor(self, floor):
"""Update value of current floor."""
if self.floor != floor:
self.history.append(floor)
self.floor = floor
if floor in self.stops:
self.stops.remove(floor)
def get_next_stop(self):
"""Get next stop."""
if self.direction: # if going up.
return min(self.stops) # return lowest stop in the list
else: # Going down
return max(self.stops) # return highest stop in the list
def build_stops(self):
"""Get floors with people waiting for elevator in current direction."""
for i, elem in enumerate(self.queues):
if [x for x in elem if self.DIR_FUNC[self.direction](x, i)]:
self.stops.add(i)
答案5:
class Dinglemouse:
def __init__(self, queues, capacity):
self.capacity, self.lift, self.queues = capacity, [], [list(row)[::-1] for row in queues]
def theLift(self):
def move_people(source, destination, floor, direction, limit=float('inf')):
return sum(cmp(source[idx], floor) == direction
and not (len(destination) < limit and destination.append(source.pop(idx)))
for idx in range(len(source) - 1, -1, -1))
def move_lift(direction):
return sum(move_people(self.lift, self.queues[floor], floor, 0) +
move_people(self.queues[floor], self.lift, floor, direction, self.capacity)
and not (stops[-1] != floor and stops.append(floor))
for floor in range(len(self.queues))[::direction])
stops, cmp = [0], lambda a, b: (a > b) - (a < b)
while move_lift(1) + move_lift(-1): pass
return stops[-1] != 0 and stops.append(0) or stops
答案6:
class Dinglemouse(object):
def __init__(self, queues, capacity):
self.queues = queues
self.capacity = capacity
self.carrying = []
self.visited = []
self.direction = "up"
self.currentFloor = 0
self.goingItsWay = [n for n in range(len(queues))]
def theLift(self):
"""
While there are still people waiting for the lift or en-route..
"""
while list(sum(self.get_queues(),())) != [] or self.get_carrying() != []:
"""
Iterate over the next floor, perhaps after the lift's direction has been altered, "break" makes sure of that
"""
for floor in self.get_goingItsWay():
newLoad = []
oldLoad = self.get_carrying()
"""
Making sure that all dependent methods know on which floor we are and listing the floors in the current direction
"""
self.set_currentFloor(floor)
self.set_goingItsWay(self.get_direction())
self.pingUnload()
self.pingLoad()
"""
Check if a direction change is needed if no passengers for any of the floors in the current direction have entered,
and letting passengers enter who may want to enter if the direction has changed
"""
self.set_direction()
self.pingLoad()
"""
Retrieving the current passengers in the lift to compare it to the load when the lift just arrived,
checking whether the lift opens its door at ground level when no queue present,
checking if the lift is at a floor where someone is waiting to go in the current direction, whether the lift is full or not,
all of the above to decide if the lift will stop at the current floor and, thus, be added to the visited list
"""
newLoad = self.get_carrying()
madeDropOff = newLoad != oldLoad
nullState = newLoad == [] and oldLoad == [] and floor == 0
stopForPushInDir = set(self.get_queues()[floor]).intersection(set(self.get_goingItsWay())) != set([])
if madeDropOff or nullState or stopForPushInDir:
self.set_visited(floor)
"""
Break out of the loop in case the lift has altered its direction
"""
break
"""
Check whether the last floor visited was at ground level and
check whether the building is empty (and thus the lift hasn't done anything but gathering dust)
.. to eventually add resp. end state or begin/zombie state (i.e. visited floor) to the visited list
"""
if self.get_currentFloor() != 0 or self.get_visited() == []:
self.set_visited(0)
"""
The Holy Grail
"""
return self.get_visited()
def pingLoad(self):
"""
Loading potential new passengers and update the lift's load and the queue at the current floor accordingly
"""
liftContents = self.get_carrying()[:]
newQueue = []
for person in self.get_queues()[self.get_currentFloor()]:
"""
Check whether the person in the queue agrees with the current direction and
whether the lift exceeded its capacity
Add to lift's load if so, place back while preserving his/her place in queue if not
"""
if person in self.get_goingItsWay() and len(liftContents) < self.get_capacity():
liftContents.append(person)
else:
newQueue.append(person)
self.carrying = liftContents[:]
self.set_queues(newQueue)
def pingUnload(self):
"""
Remove all the passengers from the lift that wanted to go to the current floor
"""
self.carrying = list(filter(lambda x: x != self.get_currentFloor(), self.get_carrying()))
def set_currentFloor(self, floor):
self.currentFloor = floor
def set_direction(self):
"""
dropInDir: checks whether any of the current lift's passengers wants to be dropped off somewhere in the current direction
waitingAbove/waitingBelow: checks if there are (non-empty) queues resp. above or below the current floor
waitingAboveButFull: checks if there are people waiting above the lift's current full, but the lift is LOADED
isGround/isTopFloor: checks whether the lift is resp. at ground level or at the top floor
"""
dropInDir = set(self.get_carrying()).difference(set(self.get_goingItsWay())) != set(self.get_carrying())
waitingAbove = set(self.get_queues()[self.get_currentFloor()+1:]) != {()}
waitingBelow = set(self.get_queues()[:self.get_currentFloor()]) != {()}
waitingAboveButFull = waitingAbove and len(self.get_carrying()) == self.get_capacity() and not dropInDir
isGround = self.get_currentFloor() == 0
isTopFloor = len(self.get_queues()) - 1 == self.get_currentFloor()
"""
Use the above to decide whether to change the lift's direction or not
"""
if self.get_direction() == "up":
if not dropInDir and not waitingAbove or isTopFloor or waitingAboveButFull:
self.set_goingItsWay("down")
self.direction = "down"
elif self.get_direction() == "down":
if not dropInDir and not waitingBelow or isGround:
self.set_goingItsWay("up")
self.direction = "up"
def set_goingItsWay(self, direction):
"""
Generates floors according to the lift's (new) direction
"""
if direction == "up":
self.goingItsWay = [n for n in range(self.get_currentFloor() + 1, len(self.get_queues()))]
elif direction == "down":
self.goingItsWay = [n for n in reversed(range(0, self.get_currentFloor()))]
def set_queues(self, newQueue):
"""
Mutability stuff
"""
self.queues = list(self.get_queues())
self.queues[self.get_currentFloor()] = tuple(newQueue)
self.queues = tuple(self.get_queues())
def set_visited(self, floor):
self.visited.append(floor)
def get_capacity(self):
return self.capacity
def get_carrying(self):
return self.carrying
def get_currentFloor(self):
return self.currentFloor
def get_direction(self):
return self.direction
def get_goingItsWay(self):
return self.goingItsWay
def get_queues(self):
return self.queues
def get_visited(self):
return self.visited
答案7:
class Dinglemouse(object):
def __init__(self, queues, capacity):
self.q = [list(i) for i in queues]
self.c = capacity
def theLift(self):
a,l,i,f,t = [0],0,[],lambda x:x!=-1,1
while any([x for x in self.q if x]) or i:
stop = False
if [x for x in i if x==l]:
stop = True
i=list(filter(lambda x:x!=l,i))
for n,p in enumerate(self.q[l]):
if p*t>l*t:
stop = True
if len(i)<self.c:
i.append(p)
self.q[l][n]=-1
self.q[l] = list(filter(f,self.q[l]))
a+=[l]*stop*(a[-1]!=l)
if 0<=l+t<len(self.q):
l+=t
else:
t*=-1
a+=[0]*(a[-1]!=0)
return a
答案8:
class Dinglemouse(object):
def __init__(self, queues, capacity):
self.queues = [list(q) for q in queues]
self.capacity = capacity
self.stops = [0]
self.scan_floor = 0
self.direction = 1 # 1 = go up one, -1 = go down one
self.passengers = []
def theLift(self):
# Run until queues and lift are empty
while any(self.queues) or self.passengers:
# Stop to release passengers wanting out
if self.scan_floor in self.passengers:
self.passengers = [p for p in self.passengers if p != self.scan_floor]
if self.stops[-1] != self.scan_floor: self.stops.append(self.scan_floor)
# Stop to pick up passengers going same direction until lift is full
for p in list(self.queues[self.scan_floor]):
if p*self.direction > self.scan_floor*self.direction:
if self.stops[-1] != self.scan_floor: self.stops.append(self.scan_floor)
if len(self.passengers) < self.capacity:
self.passengers.append(p)
self.queues[self.scan_floor].remove(p)
# Scan next floor in direction or change direction at top or bottom
if 0 <= self.scan_floor + self.direction < len(self.queues):
self.scan_floor += self.direction
else:
self.direction = -(self.direction)
# Stop at bottom floor and return list of stops
return self.stops+[0] if self.stops[-1] != 0 else self.stops
答案9:
class Dinglemouse(object):
def __init__(self, queues, capacity):
self.capacity = capacity
self.queues = [list(x) for x in queues]
self.lift = []
self.history = [0]
self.flag = True
def theLift(self):
while self.isListTrue() or self.lift:
self.scanUp()
self.scanDown()
if self.history[-1]:
self.history.append(0)
return self.history
def isListTrue(self):
for queue in self.queues:
if queue:
return True
return False
def scanUp(self):
for floorNumber, floorQueue in enumerate(self.queues):
self.flag = True
if self.lift:
self.unloadCheck(floorNumber, floorQueue)
if floorQueue:
self.loadCheck(floorNumber, floorQueue, "Up")
def scanDown(self):
for tmpNumber, floorQueue in enumerate(reversed(self.queues)):
floorNumber = len(self.queues) - 1 - tmpNumber
self.flag = True
if self.lift:
self.unloadCheck(floorNumber, floorQueue)
if floorQueue:
self.loadCheck(floorNumber, floorQueue, "Down")
def unloadCheck(self, floorNumber, floorQueue):
tmpLift = list(filter(lambda a: a != floorNumber, self.lift))
if tmpLift != self.lift:
self.history.append(floorNumber)
self.lift = tmpLift
self.flag = False
def loadCheck(self, floorNumber, floorQueue, direction):
tmpQueue = []
for queueNumber, person in enumerate(floorQueue):
if ((person > floorNumber and direction == "Up") or (person < floorNumber and direction == "Down")):
if self.flag:
if self.history[-1] != floorNumber:
self.history.append(floorNumber)
self.flag = False
if len(self.lift) + 1 <= self.capacity:
self.lift.append(person)
else:
tmpQueue.append(person)
else:
tmpQueue.append(person)
self.queues[floorNumber] = tmpQueue
答案10:
class Dinglemouse(object):
def __init__(self, queues, capacity):
self.queues = queues
self.capacity = capacity
def theLift(self):
stops = [0]
cap = self.capacity
que = [list(el)for el in self.queues]
where_stop = []
run_time = 0
for tu in que:
run_time += len(tu)
i, d = 0, 1
for b in range(run_time * len(que)):
add = False
if i in where_stop:
if i != stops[-1]:
stops.append(i)
cap += where_stop.count(i)
where_stop = list(filter(lambda a: a != i, where_stop))
if que[i] and cap != 0:
for id, j in enumerate(que[i]):
if (j > i and cap != 0 and d > 0) or (j < i and cap != 0 and d < 0) or i == len(que) - 1 and cap != 0 :
where_stop.append(j)
cap -= 1
que[i][id] = "X"
add = True
que[i] = list(filter(lambda a: a != "X", que[i]))
where_stop = where_stop
if where_stop and i != stops[-1] or j < i and d < 0 and i != stops[-1]:
for ee in que[i]:
if ee > i and d > 0:
stops.append(i)
break
elif ee < i and d < 0:
stops.append(i)
break
if add == True and i != stops[-1]:
stops.append(i)
elif que[i] and d < 0:
for r in que[i]:
if r < i:
if i != stops[-1]:
stops.append(i)
elif que[i] and d > 0:
for r in que[i]:
if r > i:
if i != stops[-1]:
stops.append(i)
i += d
if i == len(que) - 1 and d > 0 or i == 0 and d < 0:
d *= -1
if stops[-1] != 0:
stops.append(0)
return stops
歡迎各位同學加羣討論,一起學習,共同成長!