《剑指Offer》 -- 机器人的运动范围(回溯法)(Python实现)

题目描述

地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

分析

以上所提到的方格可以看做是一个(M x N)的矩阵,同样,在这个矩阵中,出了边界的格子外,其他格子都有4个相邻的格子。机器人从坐标(0,0)开始移动,当他准备进入坐标(i,j)的格子时,通过检查坐标的位数和来判断机器人是否能够进入

如果机器人能够进入坐标为(i,j)的格子,则再判断它能够进入4个相邻的格子,(i,j-1)(i,j+1)(i-1,j)(i+1,j)

显然可以使用回溯法解决,回溯法的关键是找到正确的根以及构建正确的递归环境,而正确的递归环境需要两个停止递归的约束条件:1)边界条件;2)递归停止条件

由以上分析可知根是唯一的,也就是(0,0)坐标,接下来就是不断移动坐标不断判断当前坐标是否满足条件,如果满足条件则递归判断当前坐标的四个相邻坐标是否满足条件

代码

def sumByte(num):
    # 解析行列坐标的位数,并求和
    # 思想:将数字转成字符串,再将字符串各个字符保存在列表中,接下来将列表所有字符元素转成int 
    # 型,最后累加求和
    num2str = list(str(num))
    str2num = [int(i) for i in num2str]
    return sum(str2num)


def movingCountCore(threshold, s_i, s_j, rows, cols, visited):
    # s_i,s_j 表示当前的位置节点
    # rows, cols 表示限制的区域右下角坐标
    #
    # 递归停止条件1:边界问题加上已经被访问过
    if s_i < 0 or s_j < 0 or s_i >=rows or s_j >=cols or visited[s_i][s_j]:
        return False

    # 递归停止条件2:当行列坐标的位数和大于阈值时,停止递归
    # 解析行列坐标的位数,并求和
    loc = sumByte(s_i) + sumByte(s_j)

    # 否则,调用递归
    if loc <= threshold:
        
        # 满足条件递归条件,就是说机器人可以到达坐标(s_i,s_j)
        visited[s_i][s_j] = 1
        
        # 递归判断机器人是否能到达(s_i,s_j)相邻的4个坐标
        movingCountCore(threshold, s_i - 1, s_j, rows, cols, visited)
        movingCountCore(threshold, s_i + 1, s_j, rows, cols, visited)
        movingCountCore(threshold, s_i, s_j - 1, rows, cols, visited)
        movingCountCore(threshold, s_i, s_j + 1, rows, cols, visited)
    else:
        return False


def movingCount(threshold, rows, cols):
    # 机器人从坐标(0,0)开始移动,当他准备进入坐标为(i,j)的格子时,通过检查坐标的位数和来判        
    # 断机器人是否能够进入
    # 如果机器人能够进入坐标为(i,j)的格子,则再判断它能否进入4个相邻的格子
    # (i,j-1)(i,j+1)(i-1,j)(i+1,j)
    # 使用回溯法实现
    
    # 记录表,机器人可以到达的坐标(i,j)对应 visited[i][j]=1
    # 否则,visited[i][j]=0
    visited = [[0] * cols for _ in range(rows)]
    
    # 机器人从坐标(0,0)开始移动
    movingCountCore(threshold, 0, 0, rows, cols, visited)
    
    # 统计记录表中多少个元素为1
    sumGray = 0
    for i in range(len(visited)):
        sumGray += sum(visited[i])

    return sumGray

测试

print(movingCount(15, 20, 20))

结果

359

更多关于回溯法内容

https://blog.csdn.net/qq_18254385/article/details/93993899

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值