机器人活动区域

一、题目描述

现有一个机器人,可放置于 M × N 的网格中任意位置,每个网格包含一个非负整数编号,当相邻网格的数字编号差值的绝对值小于等于 1 时,机器人可以在网格间移动。

问题: 求机器人可活动的最大范围对应的网格点数目。​

说明:​网格左上角坐标为 (0,0) ,右下角坐标为(m−1,n−1) ,机器人只能在相邻网格间上下左右移动。

二、输入输出描述

1. 输入描述

  • 第一行:两个整数 M 和 N ,M 表示网格的行数 N 表示网格的列数,1 ≤ M,N ≤ 150;
  • 后续 M 行:每行 N 个数值(数值大小用 k 表示, 0 ≤ k ≤ 50),数值间用单个空格分隔。

2. 输出描述

  • 输出一个整数,表示机器人可活动的最大区域的网格点数目。

三、示例

|----|-------------------------------------|
| 输入 | 4 4 1 2 5 2 2 4 4 5 3 5 7 1 4 6 2 4 |
| 输出 | 6 |
| 说明 | |

四、解题思路

1. 核心思想

通过广度优先搜索(BFS) 遍历矩阵中所有未访问的单元格,逐个计算其所在连通区域的大小,最终筛选出最大的区域大小 ------ 核心是 "遍历不重复 + 连通性判定 + 大小统计"。

2. 问题本质分析

问题本质是带条件的连通区域查找与大小统计

  • 连通性规则:单元格仅与 "上下左右相邻 + 数值差值≤1" 的单元格连通(非传统的 "数值相同" 连通,而是差值范围放宽到≤1)。
  • 目标:找到所有满足该连通规则的区域中,包含单元格数量最多的那个,输出其数量。
  • 关键约束:需避免重复遍历(同一单元格只能属于一个连通区域),因此需要访问标记数组。
3. 核心逻辑
  • 遍历全覆盖:逐行逐列遍历矩阵所有单元格,确保每个未访问的单元格都能触发一次 BFS,覆盖所有连通区域。
  • BFS 连通性判定:以队列作为核心数据结构,逐层扩展相邻单元格,仅纳入满足 "范围 + 访问 + 差值" 条件的单元格,统计区域大小。
  • 最大值更新:每次 BFS 计算出一个区域的大小后,与当前最大值对比,保留更大值。
4. 步骤拆解
  1. 输入读取与初始化

    • 读取矩阵尺寸 mn 和矩阵 grid
    • 初始化访问标记数组 visited(全为 false)、最大区域大小 maxSize(初始 0)、方向偏移量 dirs
  2. 遍历矩阵,触发 BFS

    • 循环遍历矩阵的每个单元格 (i,j)
      • visited[i][j] == false(未被访问),调用 BFS 计算该单元格所在连通区域的大小。
      • 用 BFS 返回的区域大小更新 maxSize(取最大值)。
  3. BFS 计算连通区域大小

    • 初始化队列,加入起始单元格 (x,y),标记为已访问,区域大小初始化为 1。
    • 队列非空时,弹出头部单元格,遍历其四个方向的相邻单元格:
      • 筛选符合条件的相邻单元格(范围合法 + 未访问 + 数值差值≤1)。
      • 满足条件则标记访问、加入队列、区域大小 + 1。
    • 队列遍历完成后,返回当前区域大小。
  4. 结果输出

    • 遍历完所有单元格后,返回并输出 maxSize(最大连通区域的大小)。

五、代码实现

java 复制代码
import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        // 读取矩阵的行数和列数
        int m = sc.nextInt();
        int n = sc.nextInt();
        // 读取矩阵内容
        int[][] grid = new int[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                grid[i][j] = sc.nextInt();
            }
        }
        // 输出最大区域的大小
        System.out.println(getResult(grid, m, n));
    }
    // 计算矩阵中最大的连通区域的大小
    public static int getResult(int[][] grid, int m, int n) {
        boolean[][] visited = new boolean[m][n]; // 访问标记数组
        int maxSize = 0;  // 记录最大的区域大小
        // 四个方向的偏移量,上下左右
        int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
        // 遍历整个矩阵
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                // 如果当前点没有被访问过,执行 BFS 计算该区域的大小
                if (!visited[i][j]) {
                    int size = bfs(grid, visited, i, j, m, n, dirs);
                    // 更新最大区域的大小
                    maxSize = Math.max(maxSize, size);
                }
            }
        }
        return maxSize;  // 返回最大的区域大小
    }
    // 使用 BFS 查找从 (x, y) 出发的连通区域的大小
    private static int bfs(int[][] grid, boolean[][] visited, int x, int y, int m, int n, int[][] dirs) {
        Queue<int[]> queue = new LinkedList<>();  // BFS 使用的队列
        queue.offer(new int[]{x, y});  // 将起始点加入队列
        visited[x][y] = true;  // 标记起始点为已访问
        int size = 1;  // 当前区域的大小,从起始点开始
        // 当队列不为空时,继续遍历
        while (!queue.isEmpty()) {
            int[] point = queue.poll();  // 弹出队列中的一个元素
            // 遍历当前点的四个方向
            for (int[] dir : dirs) {
                int newX = point[0] + dir[0];  // 计算新点的横坐标
                int newY = point[1] + dir[1];  // 计算新点的纵坐标
                // 确保新点在矩阵范围内,并且未被访问过
                // 同时新点与当前点的差值小于等于 1,才将新点加入队列
                if (newX >= 0 && newX < m && newY >= 0 && newY < n && !visited[newX][newY]
                        && Math.abs(grid[point[0]][point[1]] - grid[newX][newY]) <= 1) {
                    visited[newX][newY] = true;  // 标记新点为已访问
                    queue.offer(new int[]{newX, newY});  // 将新点加入队列
                    size++;  // 增加当前区域的大小
                }
            }
        }
        return size;  // 返回当前区域的大小
    }
}
相关推荐
晴殇i2 小时前
揭秘JavaScript中那些“不冒泡”的DOM事件
前端·javascript·面试
孟陬2 小时前
国外技术周刊 #1:Paul Graham 重新分享最受欢迎的文章《创作者的品味》、本周被划线最多 YouTube《如何在 19 分钟内学会 AI》、为何我不
java·前端·后端
想用offer打牌2 小时前
一站式了解四种限流算法
java·后端·go
绝无仅有2 小时前
Redis过期删除与内存淘汰策略详解
后端·面试·架构
绝无仅有2 小时前
Redis大Key问题排查与解决方案全解析
后端·面试·架构
华仔啊3 小时前
Java 开发千万别给布尔变量加 is 前缀!很容易背锅
java
AAA梅狸猫3 小时前
Looper.loop() 循环机制
面试
AAA梅狸猫3 小时前
Handler基本概念
面试
也些宝3 小时前
Java单例模式:饿汉、懒汉、DCL三种实现及最佳实践
java