Sword13——机器人的运动范围
方法1——DFS
- 思路:从第一个单元格开始一直向下搜索,并统计个数,当无法继续执行时,则进行回溯并剪枝,重新开始另一条新路径,直到最后所有可达路径均已遍历,返回结果即可
- 特殊情况与临界分析:k等于0时,直接返回1即可,也可包含在DFS中
- 终止条件:每当碰到比k还要大的单元格时,即向上回溯剪枝
- 步骤:
- 定义一个全局辅助矩阵,用于记录矩阵中单元格已被访问
- 将坐标m和n、以及数字k提升作用域至全局,便于DFS中使用
- 进行相关全局变量的赋值
- 开始递归,并返回统计结果
- 递归方法
- 参数:当前单元格的坐标i和j
- 当单元格不符合规则时,直接退出
- 符合规则时,将辅助矩阵中设置为可行true
- 递归对右边和下面的两个单元格进行判断,结果要加上自身符合的1
- 计算单个数的总和方法
boolean[][] vistied;
int m, n, k;
public int movingCount(int m, int n, int k) {
this.m = m;
this.n = n;
this.k = k;
this.visited = new boolean[m][n];
return dfs(0, 0);
}
private int dfs(int i, int j) {
if (i >= m || j >= n || visited[i][j] || get(i) + get(j) > k) {
return 0;
}
visited[i][j] = true;
return 1 + dfs(i, j + 1) + dfs(i + 1, j);
}
private int get(int val) {
int res = 0;
while (val != 0) {
res += val % 10;
val /= 10;
}
return res;
}
方法2——BFS
- 思路:广度优先遍历,一般涉及到队列,将遍历到的可行单元格依次入队,从中每弹出一个,对其右边和下面分析是否可行,可行则入队,之后重复操作即可
- 特殊情况与临界分析:k等于0时,直接返回1即可
- 终止条件:队列为空时,证明已获取所有可达单元格
- 步骤:
- k等于0的特殊情况
- 定义辅助队列,其中存放的是每一个单元格坐标int[]
- 向辅助队列中加入第一个单元格,确保队列非空
- 定义辅助矩阵,用于记录被访问过的位置
- 队列中入队元素位置,在辅助队列中设置为true
- 定义右移或下移的节点,便于将其加入
- 定义可达节点的结果数量
- 循环条件:队列非空
- while循环
- 从队列中弹出一个单元格
- 得出此节点的x、y坐标
- for循环计算两次,对其右、下坐标节点判断是否符合条件
- 根据右移或下移情况,得出下一个坐标(利用到定义的右移或下移节点)
- 判断单元格不符合规则的情况
- 符合规则,将其入队
- 将对应位置的辅助矩阵处设置为true
- 将结果值进行加1
- 返回结果值
- 计算单个数的总和方法
public int movingCount(int m, int n, int k) {
if (k == 0) return 1;
Queue<int[]> queue = new LinkedList<>();
queue.offer(new int[]{0, 0});
boolean[][] visited = new boolean[m][n];
visited[0][0] = true;
int[] dx = {0, 1};
int[] dy = {1, 0};
int res = 1;
while (!queue.isEmpty()) {
int[] cell = queue.poll();
int x = cell[0], y = cell[1];
for (int i = 0; i < 2; i++) {
int nx = x + dx[i], ny = y + dy[i];
if (nx >= m || ny >= n || visited[nx][ny] || get(nx) + get(ny) > k) {
continue;
}
queue.offer(new int[]{nx, ny});
visited[nx][ny] = true;
res++;
}
}
return res;
}
private int get(int val) {
int res = 0;
while (val != 0) {
res += val % 10;
val /= 10;
}
return res;
}