#LC1254. 封闭岛屿的数量
封闭岛屿的数量
你好,同学!在掌握了基础的“岛屿数量”统计后,我们今天进入进阶课题:“封闭岛屿的数量”。
这道题在 NOI 竞赛中属于典型的**“带边界条件的连通块搜索”**。虽然核心依然是 DFS/BFS,但它引入了一个关键逻辑:如何定义并判断一个连通块是否“触碰了边界”。
一、 题目描述:封闭岛屿的数量 (Number of Closed Islands)
题目背景: 在资源勘探中,不仅要统计区域,还要区分哪些区域是完全被包围在内部的“核心区”。
任务描述:
给你一个大小为 的二维网格 grid。其中:
0表示陆地。1表示水域。 注意:本题中0是陆地,这与基础题不同。 封闭岛屿 是指完全由水域包围的岛屿(上、下、左、右)。如果一个岛屿触碰到了网格的边界(即第一行、最后一行、第一列、最后一列),那么它就不是封闭的,因为它有一边被网格边缘挡住,而不是被水包围。
请计算网格中“封闭岛屿”的总数。
输入格式:
第一行包含两个整数 和 ,。
接下来的 行,每行包含 个整数(0 或 1),用空格分隔。
输出格式: 输出一个整数,表示封闭岛屿的数量。
样例 1:
输入:
5 8
1 1 1 1 1 1 1 0
1 0 0 0 0 1 1 0
1 0 1 0 1 1 1 0
1 0 0 0 0 1 0 1
1 1 1 1 1 1 1 0
输出:
2
样例数据说明:
虽然网格里有好几个由 0 组成的连通块,但只有中间两个完全被 1 包围。最右侧那一列的 0 触碰了边界,不计入封闭岛屿。
二、 预备知识点
- Flood Fill (种子填充): 从一个点开始扩散。
- 边界处理 (Boundary Condition): 识别处于 的节点。
- 逆向思维/预处理: 与其在搜索过程中判断是否封闭,不如提前排除“非封闭”的干扰项。
三、 启发式引导:草稿纸上的排除法
当题目要求我们找“不接触边界”的连通块时,在 NOI 竞赛中我们通常有两种策略:
策略 A:排除法(教练推荐:思路最清晰)
- 第一步: 扫描网格的四条边。
- 第二步: 如果在边缘发现了陆地
0,说明它所属的整个岛屿都不是封闭的。 - 第三步: 立即以这些边缘
0为起点,进行一次 DFS,把与之相连的所有陆地统统变成水域1。 - 第四步: 处理完所有边缘岛屿后,剩下的
0连通块必然是封闭的。现在只需要按部就班统计“岛屿数量”即可。
策略 B:搜索标志位
在 DFS 遍历一个连通块时,设置一个全局变量 isClosed = true。如果遍历过程中遇到了 x == 0 或 x == M-1 等情况,将 isClosed 改为 false。
复杂度分析:
- 时间复杂度: 。无论哪种策略,每个格子最多被访问两次。
- 空间复杂度: 。递归栈深度。
四、 算法流程图 (Mermaid 风格)
我们采用策略 A(预处理排除法)进行逻辑绘制:
graph TD
Start("开始") --> Step1("第一步: 排除边缘岛屿")
Step1 --> LoopEdge("遍历四条边界上的每个格子")
LoopEdge --> Check0{"当前格子是 0 吗?"}
Check1 -- "是" --> Fill1("以该点 DFS 将连通块全部填充为 1")
Check0 -- "是" --> Fill1
Check0 -- "否" --> NextEdge("检查下一个边缘点")
Fill1 --> NextEdge
NextEdge --> AllEdgeDone{"边缘遍历完了吗?"}
AllEdgeDone -- "是" --> Step2("第二步: 统计内部岛屿")
Step2 --> ScanAll("遍历网格内部所有点 i, j")
ScanAll --> Found0{"发现 grid_i_j == 0?"}
Found0 -- "是" --> AnsAdd("封闭岛屿计数 ans 加 1")
AnsAdd --> DFS2("以该点 DFS 将连通块填充为 1")
DFS2 --> NextPoint("继续扫描下一个点")
Found0 -- "否" --> NextPoint
NextPoint --> AllDone{"全网格扫描完了吗?"}
AllDone -- "是" --> Output("输出 ans")
五、 读题理解关键词
在 NOI 考试中,理解此类题意的关键词在于:
- “封闭” (Closed): 意味着只要有一个点出界,整个集合就失效。这种“一票否决制”往往预示着可以先处理掉所有“不合规”的集合。
- “0 和 1 的含义”: 陆地和水域的数字定义经常反转,读题时一定要在草稿纸上圈出来,避免写反。
- “上下左右”: 明确是四连通还是八连通。
- 边界范围: 的数据范围非常小,DFS 完全不会爆栈,甚至可以使用最朴素的算法。
教练笔记: 策略 A 的美妙之处在于它把一个复杂的问题(边搜边判断)拆解成了两个简单的问题(先删边界,再数中间)。这种“简化问题模型”的能力,是冲击金牌的重要素质。加油!