• 左神算法题系列:动态规划机器人走路


    机器人走路

    假设有排成一行的N个位置记为1~N,N一定大于或等于2
    开始时机器人在其中的start位置上(start一定是1~N中的一个)
    如果机器人来到1位置,那么下一步只能往右来到2位置;
    如果机器人来到N位置,那么下一步只能往左来到N-1位置;
    如果机器人来到中间位置,那么下一步可以往左走或者往右走;
    规定机器人必须走K步,最终能来到aim位置(P也是1~N中的一个)的方法有多少种
    给定四个参数 N,start,aim,K 返回能走到的方法数

    递归思路

    1、当cur在1位置时,只能向2位置移动
    2、当cur在N位置时,只能向N-1位置移动
    3、当cur在中间位置,可以向cur+1位置移动、也可以向cur-1位置移动
    4、如果剩余步数刚好走完时,来到目标位置,返回1,否则返回0

    class RobotWalk(object):
        def ways_a(self, pos, steps, start, target):
            """
    
            :param pos: 总共有pos个位置
            :param steps: 可以走的步数
            :param start: 开始位置
            :param target: 目标位置
            :return:
            """
            if pos < 2 or steps < 1 or start < 1 or start > pos or target < 1 or target > pos:
                return 0
            return self.process_a(pos, start, steps, target)
    
        def process_a(self, pos, cur, rest, target):
            """
            :param pos: 总共有pos个位置
            :param cur: 当前来到的位置
            :param rest: 还剩下的步数
            :param target: 目标位置
            :return: 机器人从cur出发,走过rest步之后,最终停留在target的方法数
            """
            # 步数走完时,如果机器人刚好到达目标位置,则返回1
            if rest == 0:
                return 1 if cur == target else 0
            # 如果在1位置,只能向右走 -> cur+1
            if cur == 1:
                return self.process_a(pos, cur + 1, rest - 1, target)
            # 如果在最后一个位置,只能向左 -> cur-1
            if cur == pos:
                return self.process_a(pos, cur - 1, rest - 1, target)
            # 中间位置 既能向左又能向右
            return self.process_a(pos, cur + 1, rest - 1, target) + self.process_a(pos, cur - 1, rest - 1, target)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    动态规划

    加缓存

    class RobotWalk(object):
        def ways_b(self, pos, steps, start, target):
            """
    
            :param pos: 总共有pos个位置
            :param steps: 可以走的步数
            :param start: 开始位置
            :param target: 目标位置
            :return:
            """
            if pos < 2 or steps < 1 or start < 1 or start > pos or target < 1 or target > pos:
                return 0
            # 转移条件 剩下的步数 和 当前位置
            # 当前位置cur 范围 1~pos
            # 剩余步数rest 范围 0~steps
            # steps(总步数) 列 pos(总共位置数) 行的数组
            cache = [[-1] * (steps + 1) for _ in range(pos + 1)]
            return self.process_b(pos, start, steps, target, cache)
    
        def process_b(self, pos, cur, rest, target, cache):
            """
            加缓存减少重复计算
            :param pos:
            :param cur:
            :param rest:
            :param target:
            :param cache:
            :return:
            """
            # 当前位置没有计算过,则计算后存入缓存,否则直接返回缓存数据
            if cache[cur][rest] == -1:
                # 步数走完时,如果机器人刚好到达目标位置,则返回1
                if rest == 0:
                    index = 1 if cur == target else 0
                elif cur == 1:
                    index = self.process_b(pos, 2, rest - 1, target, cache)
                elif cur == pos:
                    index = self.process_b(pos, pos - 1, rest - 1, target, cache)
                else:
                    index = self.process_b(pos, cur + 1, rest - 1, target, cache) + \
                            self.process_b(pos, cur - 1, rest - 1, target, cache)
                cache[cur][rest] = index
            return cache[cur][rest]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    假如:
    位置数 pos=6
    剩余步数steps=5
    开始位置start=1
    目标位置target=4
    cur为当前位置
    创建动态表dp 行代表位置数 pos(1,pos), 列代表剩余步数rest(0,steps)
    根据递归条件填表:
    1、当剩余步数为0时,刚好来到target位置,dp值为1,如果在其他位置,说明未到目标位置,dp值为0
    即:dp[cur][rest] = dp[4][0] = 1
    2、当cur=1时,只能向2位置移动,都依赖dp[2][rest-1]位置的值
    3、当cur=pos时,只能向pos-1位置移动,都依赖dp[pos-1][rest-1]位置的值
    4、当1 最终求dp[start][rest] --> dp[1][5] = 4

    | cur/rest

    位置/剩余步数012345
    0xxxxxx
    1000104
    2001040
    30103010
    4102060
    5010309
    6001030

    代码实现

    class RobotWalk(object):
        def ways_c(self, pos, steps, start, target):
            """
            :param pos: 总共有pos个位置
            :param steps: 可以走的步数
            :param start: 开始位置
            :param target: 目标位置
            :return:
            """
            if pos < 2 or steps < 1 or start < 1 or start > pos or target < 1 or target > pos:
                return 0
            # 当前位置cur 范围 1~pos
            # 剩余步数rest 范围 0~steps
            # steps(总步数) 列 pos(总共位置数) 行的数组
            dp = [[0] * (steps + 1) for _ in range(pos + 1)]
            # 当剩余0步时,刚好来到target位置 则dp值为1, 其他位置值为0
            dp[target][0] = 1
            # 列
            for col in range(1, steps + 1):
                # 第一行依赖左下元素
                dp[1][col] = dp[2][col - 1]
                # 中间行依赖左下和左上
                for row in range(1, pos):
                    dp[row][col] = dp[row + 1][col - 1] + dp[row - 1][col - 1]
                # 最末行依赖左上元素
                dp[pos][col] = dp[pos - 1][col - 1]
    
            return dp[start][steps]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
  • 相关阅读:
    HTML静态网页成品作业(HTML+CSS)——美食火锅介绍网页(1个页面)
    开源教育论坛| ChinaOSC
    ---线程3续
    Linux文件系统
    Qt不能安装自己想要的版本,如Qt 5.15.2
    SpringBatch(11):ItemProcessor
    泛型实例运用
    【如何利用扩展卡尔曼滤波解决跟踪毫米波雷达目标】
    前端如何控制并发请求数量?
    半导体工艺控制设备1
  • 原文地址:https://blog.csdn.net/u010442378/article/details/134099270