剑指Offer:[第14天 搜索与回溯算法(中等)]--->机器人的运动范围


一、题目描述

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

示例1:

输入:m = 2, n = 3, k = 1
输出:3

示例2:

输入:m = 3, n = 1, k = 0
输出:1

提示:

1<=n, m<=100
0<=k<=20

二、思路分析

注:思路分析中的一些内容和图片参考自力扣各位前辈的题解,感谢他们的无私奉献

思路

本问题是典型的矩阵搜索问题,可使用深度优先搜索(DFS)+剪枝解决
深度优先搜索: 可以理解为暴力法模拟机器人在矩阵中的所有路径。DFS通过递归,先朝一个方向搜到底,再回溯至上个节点,沿另一个方向搜索,以此类推
剪枝:在搜索中,遇到数位和超出目标值、此元素已访问,则应立即返回,称之为 可行性剪枝
可达解分析:
根据数位和增量公式得知,数位和每逢进位突变一次。根据此特点,矩阵中满足数位和的解构成的几何形状形如多个等腰直角三角形,每个三角形的直角顶点位于0, 10, 20, ...等数位和突变的矩阵索引处。三角形内的解虽然都满足数位和要求,但由于机器人每步只能走一个单元格,而三角形间不一定是连通的,因此机器人不一定能到达,称之为不可达解。同理,可到达的解称为可达解(本题求此解)。
----图例展示了 n,m=20, k∈[6,19]的可达解、不可达解、非解以及连通性的变化
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
根据可达解的结构和连通性,易推出机器人可仅通过向右和向下移动,访问所有可达解。
----三角形内部:全部连通,易证
----两三角形连通处:若某三角形内的解为可达解,则必与其左边或上边的三角形连通(即相交),即机器人必可从左边或上边走进此三角形。
在这里插入图片描述
算法流程:
①首先分配一个二维矩阵visited,用于记录各个节点是否被访问,所有元素初始值为0
②从起始点开始进行DFS,DFS的流程如下:
----判断当前行列是否越界、数位和是否超出目标值k、当前元素是否已经访问。如果满足其一,则返回0,代表不可达解
----如果都不满足,则将visited矩阵对应位置置为true
----设置回溯返回值,返回1+右方搜索的可达解总数+下方搜索的可达解总数,代表从本单元格递归搜索的可达解总数
案例分析:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
复杂度分析:
设矩阵行列数分别为MN
时间复杂度 O ( M N ) \rm{O(MN)} O(MN):最差情况下,机器人遍历矩阵所有单元格,此时时间复杂度为O(MN)
空间复杂度 O ( M N ) \rm{O(MN)} O(MN):需要使用一个二维的visited数组,使用O(MN)的额外空间


三、整体代码

整体代码如下

//取出各位数并加起来
int compare_k(int i, int k){
    int sum = 0;
    while(i >0 ){
        sum += i%10;
        i/=10;
    }
    return sum;
}

int dfs(int m, int n, int k, int i, int j, int** visited){
    /*
    如果行或列越过边界、各位数值加起来大于K、当前位置的值已经被访问,则返回0,代表这一步走不了。
    */
    if(i >= m || j >= n || compare_k(i, k) + compare_k(j, k) > k || visited[i][j] == 1) return 0;
    visited[i][j] = 1;  //如果可以走,则将这个点设置为已访问
    //继续递归遍历右边和下边的点
    return 1 + dfs(m, n, k, i + 1, j, visited) + dfs(m, n, k, i, j + 1, visited);
}

int movingCount(int m, int n, int k){
    //分配二维的visited矩阵
    int** visited = (int**)malloc(sizeof(int*)*m);
    for (int i = 0; i < m; i++) {
        visited[i] = (int *)calloc(n, sizeof(int));
    }
    //从起始点开始进行DFS
    return dfs(m,n,k,0,0,visited);
}

运行,测试通过
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知初与修一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值