Python練習題答案: 電梯【難度:5級】--景越Python編程實例訓練營,1000道上機題等你來挑戰

電梯【難度: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​




Python基礎訓練營景越Python基礎訓練營QQ羣

在這裏插入圖片描述
歡迎各位同學加羣討論,一起學習,共同成長!

發佈了682 篇原創文章 · 獲贊 8 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章