#LC695. 岛屿的最大面积

岛屿的最大面积

你好!作为金牌教练,我们已经完成了“统计岛屿个数”、“判断封闭岛屿”、“计算飞地像素”的专项训练。今天,我们要挑战岛屿系列的第四个维度:“岛屿的最大面积”

这道题在逻辑上要求我们在搜索的过程中,不仅要“走到”,还要“带回信息”。这是从单纯的连通性搜索连通块属性维护的进阶。


一、 题目描述:岛屿的最大面积 (Max Area of Island)

题目背景: 在海洋地理信息系统中,我们需要找出面积最大的岛屿以建立科研基地。

任务描述: 给你一个大小为 M×NM \times N 的二进制矩阵 grid

  • 岛屿是由一些相邻的 1 (代表土地) 构成的组合,这里的“相邻”要求两个 1 必须在水平或者垂直方向上相邻。
  • 你可以假设 grid 的四个边缘都被 0 (代表水) 包围着。
  • 岛屿的面积是该岛屿中具有土地条件的单元格数目。
  • 请计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0

输入格式: 第一行包含两个整数 MMNN1M,N501 \le M, N \le 50。 接下来的 MM 行,每行包含 NN 个用空格分隔的整数(01)。

输出格式: 输出一个整数,表示最大的岛屿面积。

样例 1:

输入:

8 13
0 0 1 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 0 0 0
0 1 1 0 1 0 0 0 0 0 0 0 0
0 1 0 0 1 1 0 0 1 0 1 0 0
0 1 0 0 1 1 0 0 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1 1 1 0 0 0
0 0 0 0 0 0 0 1 1 0 0 0 0

输出:

6

样例 2:

输入:

1 1
0

输出:

0

二、 预备知识点

  1. 深度优先搜索 (DFS) 的返回值: 理解如何通过递归函数返回当前子树/连通块的大小。
  2. 全局最优解维护: 在遍历过程中不断更新 max_ans
  3. 隐式图遍历: 依然是网格图的四连通模型。
  4. 状态重置 (访问标记): 确保每个陆地单位只被计算一次。

三、 启发式引导:将思路写在草稿纸上

请在纸上画一个小型的 3×33 \times 3 陆地块,跟着我的步骤操作:

1. 核心逻辑:带信息的“回声”

  • 单纯搜索(前几课): 只要走到新格子,就把它染成 0。
  • 计算面积(本课):
    • 当你站在格子 (i,j)(i, j) 时,你问周围四个邻居:“你们那边相连的陆地一共有多少个?”
    • 邻居回答后,你把他们的结果加起来,再加上你自己(1个)
    • 这就是典型的递归:return 1 + dfs(上) + dfs(下) + dfs(左) + dfs(右);

2. 时间与空间复杂度分析

  • 时间复杂度: 每个格子依然只被访问一次。O(M×N)O(M \times N)
  • 空间复杂度: 递归深度。O(M×N)O(M \times N)。对于 50×5050 \times 50 的规模,完全不需要担心栈溢出。

3. 优化建议

  • 原地修改: 访问过的 1 立即改为 0,避免使用 visited 数组增加空间开销。
  • 边界提前剪枝: 在调用递归前检查坐标合法性。

四、 算法流程图 (Mermaid 风格)

请注意,在 NOI 风格中,我们通常将 dfs 定义为一个返回 int 的函数:

graph TD
    Start("开始") --> InitAns("初始化 max_area 等于 0")
    InitAns --> LoopI("遍历行 i 从 0 到 M-1")
    LoopI --> LoopJ("遍历列 j 从 0 到 N-1")
    LoopJ --> Check1{"grid_i_j 是 1 吗?"}
    
    Check1 -- "是" --> CallDFS("调用 dfs_function 统计当前岛屿面积")
    CallDFS --> UpdateMax("max_area 等于 max_area 与 current_area 的较大值")
    UpdateMax --> LoopJNext("检查下一个格子")
    
    Check1 -- "否" --> LoopJNext
    
    subgraph DFS_Function
    D1("当前格子标记为 0") --> D2("初始化 count 等于 1")
    D2 --> D3("递归获取上下左右四个方向的面积和")
    D3 --> D4("返回 count 加 累计面积")
    end
    
    LoopJNext --> EndJ{"列遍历结束?"}
    EndJ -- "否" --> LoopJ
    EndJ -- "是" --> EndI{"行遍历结束?"}
    EndI -- "否" --> LoopI
    EndI -- "是" --> Output("输出 max_area")

五、 读题理解关键词

在 NOI 竞赛读题时,如何敏锐捕捉本题与其他岛屿题的区别?

  1. “最大” (Max):
    • 这是一个典型的极值问题
    • 策略: 需要一个全局变量来记录过程中的最大值,每次 DFS 结束后进行比对。
  2. “单元格数目” (Number of units):
    • 确定了度量标准:面积 = 格子的个数。
    • 策略: DFS 必须有返回值,或者在 DFS 内部累加一个计数器。
  3. “水平或垂直” (Horizontal or Vertical):
    • 再次确认是四连通。如果是八连通,面积计算会完全不同。
  4. 数据范围 (50):
    • 这是一个非常友好的范围。即使你的递归写得不够精炼,或者使用了较多的辅助空间,也很难超时。这意味着你可以更关注代码的准确性

教练点评: “岛屿的最大面积”是搜索算法中“信息回传”的敲门砖。当你习惯了让递归函数带回一个数字(面积)而不是简单的布尔值(是否连通)时,你就已经半只脚踏进了树形 DP 或者更高级搜索剪枝的大门。加油!