题目描述
地上有一个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