参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们受益!

# 101. 孤岛的总面积 [卡码网:101. 孤岛的总面积](https://kamacoder.com/problempage.php?pid=1173) 题目描述 给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿指的是由水平或垂直方向上相邻的陆地单元格组成的区域,且完全被水域单元格包围。孤岛是那些位于矩阵内部、所有单元格都不接触边缘的岛屿。 现在你需要计算所有孤岛的总面积,岛屿面积的计算方式为组成岛屿的陆地的总数。 输入描述 第一行包含两个整数 N, M,表示矩阵的行数和列数。之后 N 行,每行包含 M 个数字,数字为 1 或者 0。 输出描述 输出一个整数,表示所有孤岛的总面积,如果不存在孤岛,则输出 0。 输入示例 ``` 4 5 1 1 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 1 ``` 输出示例: 1 提示信息: ![](https://file1.kamacoder.com/i/algo/20240517105557.png) 在矩阵中心部分的岛屿,因为没有任何一个单元格接触到矩阵边缘,所以该岛屿属于孤岛,总面积为 1。 数据范围: 1 <= M, N <= 50。 ## 思路 **[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[图论:岛屿问题再出新花样 | 深搜优先搜索 | 卡码网:101.孤岛总面积](https://www.bilibili.com/video/BV1mmZJYRESc),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 本题使用dfs,bfs,并查集都是可以的。 本题要求找到不靠边的陆地面积,那么我们只要从周边找到陆地然后 通过 dfs或者bfs 将周边靠陆地且相邻的陆地都变成海洋,然后再去重新遍历地图 统计此时还剩下的陆地就可以了。 如图,在遍历地图周围四个边,靠地图四边的陆地,都为绿色, ![](https://file1.kamacoder.com/i/algo/20220830104632.png) 在遇到地图周边陆地的时候,将1都变为0,此时地图为这样: ![](https://file1.kamacoder.com/i/algo/20220830104651.png) 然后我们再去遍历这个地图,遇到有陆地的地方,去采用深搜或者广搜,边统计所有陆地。 如果对深搜或者广搜不够了解,建议先看这里:[深度优先搜索精讲](./图论深搜理论基础.md),[广度优先搜索精讲](./图论广搜理论基础.md)。 采用深度优先搜索的代码如下: ```CPP #include #include using namespace std; int dir[4][2] = {-1, 0, 0, -1, 1, 0, 0, 1}; // 保存四个方向 void dfs(vector>& grid, int x, int y) { grid[x][y] = 0; for (int i = 0; i < 4; i++) { // 向四个方向遍历 int nextx = x + dir[i][0]; int nexty = y + dir[i][1]; // 超过边界 if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue; // 不符合条件,不继续遍历 if (grid[nextx][nexty] == 0) continue; dfs (grid, nextx, nexty); } return; } int main() { int n, m; cin >> n >> m; vector> grid(n, vector(m, 0)); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> grid[i][j]; } } // 从左侧边,和右侧边 向中间遍历 for (int i = 0; i < n; i++) { if (grid[i][0] == 1) dfs(grid, i, 0); if (grid[i][m - 1] == 1) dfs(grid, i, m - 1); } // 从上边和下边 向中间遍历 for (int j = 0; j < m; j++) { if (grid[0][j] == 1) dfs(grid, 0, j); if (grid[n - 1][j] == 1) dfs(grid, n - 1, j); } int count = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (grid[i][j] == 1) count++; } } cout << count << endl; } ``` 采用广度优先搜索的代码如下: ```CPP #include #include #include using namespace std; int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 四个方向 void bfs(vector>& grid, int x, int y) { queue> que; que.push({x, y}); grid[x][y] = 0; // 只要加入队列,立刻标记 while(!que.empty()) { pair cur = que.front(); que.pop(); int curx = cur.first; int cury = cur.second; for (int i = 0; i < 4; i++) { int nextx = curx + dir[i][0]; int nexty = cury + dir[i][1]; if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue; // 越界了,直接跳过 if (grid[nextx][nexty] == 1) { que.push({nextx, nexty}); grid[nextx][nexty] = 0; // 只要加入队列立刻标记 } } } } int main() { int n, m; cin >> n >> m; vector> grid(n, vector(m, 0)); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> grid[i][j]; } } // 从左侧边,和右侧边 向中间遍历 for (int i = 0; i < n; i++) { if (grid[i][0] == 1) bfs(grid, i, 0); if (grid[i][m - 1] == 1) bfs(grid, i, m - 1); } // 从上边和下边 向中间遍历 for (int j = 0; j < m; j++) { if (grid[0][j] == 1) bfs(grid, 0, j); if (grid[n - 1][j] == 1) bfs(grid, n - 1, j); } int count = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (grid[i][j] == 1) count++; } } cout << count << endl; } ``` ## 其他语言版本 ### Java ``` java import java.util.*; public class Main { private static int count = 0; private static final int[][] dir = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}}; // 四个方向 private static void bfs(int[][] grid, int x, int y) { Queue que = new LinkedList<>(); que.add(new int[]{x, y}); grid[x][y] = 0; // 只要加入队列,立刻标记 count++; while (!que.isEmpty()) { int[] cur = que.poll(); int curx = cur[0]; int cury = cur[1]; for (int i = 0; i < 4; i++) { int nextx = curx + dir[i][0]; int nexty = cury + dir[i][1]; if (nextx < 0 || nextx >= grid.length || nexty < 0 || nexty >= grid[0].length) continue; // 越界了,直接跳过 if (grid[nextx][nexty] == 1) { que.add(new int[]{nextx, nexty}); count++; grid[nextx][nexty] = 0; // 只要加入队列立刻标记 } } } } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int m = scanner.nextInt(); int[][] grid = new int[n][m]; // 读取网格 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { grid[i][j] = scanner.nextInt(); } } // 从左侧边,和右侧边向中间遍历 for (int i = 0; i < n; i++) { if (grid[i][0] == 1) bfs(grid, i, 0); if (grid[i][m - 1] == 1) bfs(grid, i, m - 1); } // 从上边和下边向中间遍历 for (int j = 0; j < m; j++) { if (grid[0][j] == 1) bfs(grid, 0, j); if (grid[n - 1][j] == 1) bfs(grid, n - 1, j); } count = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (grid[i][j] == 1) bfs(grid, i, j); } } System.out.println(count); } } ``` ### Python #### 深搜版 ```python position = [[1, 0], [0, 1], [-1, 0], [0, -1]] count = 0 def dfs(grid, x, y): global count grid[x][y] = 0 count += 1 for i, j in position: next_x = x + i next_y = y + j if next_x < 0 or next_y < 0 or next_x >= len(grid) or next_y >= len(grid[0]): continue if grid[next_x][next_y] == 1: dfs(grid, next_x, next_y) n, m = map(int, input().split()) # 邻接矩阵 grid = [] for i in range(n): grid.append(list(map(int, input().split()))) # 清除边界上的连通分量 for i in range(n): if grid[i][0] == 1: dfs(grid, i, 0) if grid[i][m - 1] == 1: dfs(grid, i, m - 1) for j in range(m): if grid[0][j] == 1: dfs(grid, 0, j) if grid[n - 1][j] == 1: dfs(grid, n - 1, j) count = 0 # 将count重置为0 # 统计内部所有剩余的连通分量 for i in range(n): for j in range(m): if grid[i][j] == 1: dfs(grid, i, j) print(count) ``` #### 广搜版 ```python from collections import deque # 处理输入 n, m = list(map(int, input().split())) g = [] for _ in range(n): row = list(map(int, input().split())) g.append(row) # 定义四个方向、孤岛面积(遍历完边缘后会被重置) directions = [[0,1], [1,0], [-1,0], [0,-1]] count = 0 # 广搜 def bfs(r, c): global count q = deque() q.append((r, c)) g[r][c] = 0 count += 1 while q: r, c = q.popleft() for di in directions: next_r = r + di[0] next_c = c + di[1] if next_c < 0 or next_c >= m or next_r < 0 or next_r >= n: continue if g[next_r][next_c] == 1: q.append((next_r, next_c)) g[next_r][next_c] = 0 count += 1 for i in range(n): if g[i][0] == 1: bfs(i, 0) if g[i][m-1] == 1: bfs(i, m-1) for i in range(m): if g[0][i] == 1: bfs(0, i) if g[n-1][i] == 1: bfs(n-1, i) count = 0 for i in range(n): for j in range(m): if g[i][j] == 1: bfs(i, j) print(count) ``` ```python direction = [[1, 0], [-1, 0], [0, 1], [0, -1]] result = 0 # 深度搜尋 def dfs(grid, y, x): grid[y][x] = 0 global result result += 1 for i, j in direction: next_x = x + j next_y = y + i if (next_x < 0 or next_y < 0 or next_x >= len(grid[0]) or next_y >= len(grid) ): continue if grid[next_y][next_x] == 1 and not visited[next_y][next_x]: visited[next_y][next_x] = True dfs(grid, next_y, next_x) # 讀取輸入值 n, m = map(int, input().split()) grid = [] visited = [[False] * m for _ in range(n)] for i in range(n): grid.append(list(map(int, input().split()))) # 處理邊界 for j in range(m): # 上邊界 if grid[0][j] == 1 and not visited[0][j]: visited[0][j] = True dfs(grid, 0, j) # 下邊界 if grid[n - 1][j] == 1 and not visited[n - 1][j]: visited[n - 1][j] = True dfs(grid, n - 1, j) for i in range(n): # 左邊界 if grid[i][0] == 1 and not visited[i][0]: visited[i][0] = True dfs(grid, i, 0) # 右邊界 if grid[i][m - 1] == 1 and not visited[i][m - 1]: visited[i][m - 1] = True dfs(grid, i, m - 1) # 計算孤島總面積 result = 0 # 初始化,避免使用到處理邊界時所產生的累加值 for i in range(n): for j in range(m): if grid[i][j] == 1 and not visited[i][j]: visited[i][j] = True dfs(grid, i, j) # 輸出孤島的總面積 print(result) ``` ### Go ``` go package main import ( "fmt" ) var count int var dir = [4][2]int{{0, 1}, {1, 0}, {-1, 0}, {0, -1}} // 四个方向 func bfs(grid [][]int, x, y int) { queue := [][2]int{{x, y}} grid[x][y] = 0 // 只要加入队列,立刻标记 count++ for len(queue) > 0 { cur := queue[0] queue = queue[1:] curx, cury := cur[0], cur[1] for i := 0; i < 4; i++ { nextx := curx + dir[i][0] nexty := cury + dir[i][1] if nextx < 0 || nextx >= len(grid) || nexty < 0 || nexty >= len(grid[0]) { continue // 越界了,直接跳过 } if grid[nextx][nexty] == 1 { queue = append(queue, [2]int{nextx, nexty}) count++ grid[nextx][nexty] = 0 // 只要加入队列立刻标记 } } } } func main() { var n, m int fmt.Scan(&n, &m) grid := make([][]int, n) for i := range grid { grid[i] = make([]int, m) } for i := 0; i < n; i++ { for j := 0; j < m; j++ { fmt.Scan(&grid[i][j]) } } // 从左侧边,和右侧边向中间遍历 for i := 0; i < n; i++ { if grid[i][0] == 1 { bfs(grid, i, 0) } if grid[i][m-1] == 1 { bfs(grid, i, m-1) } } // 从上边和下边向中间遍历 for j := 0; j < m; j++ { if grid[0][j] == 1 { bfs(grid, 0, j) } if grid[n-1][j] == 1 { bfs(grid, n-1, j) } } // 清空之前的计数 count = 0 // 遍历所有位置 for i := 0; i < n; i++ { for j := 0; j < m; j++ { if grid[i][j] == 1 { bfs(grid, i, j) } } } fmt.Println(count) } ``` ### Rust ### JavaScript #### 深搜版 ```javascript const r1 = require('readline').createInterface({ input: process.stdin }); // 创建readline接口 let iter = r1[Symbol.asyncIterator](); // 创建异步迭代器 const readline = async () => (await iter.next()).value; let graph // 地图 let N, M // 地图大小 let count = 0 // 孤岛的总面积 const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]] //方向 // 读取输入,初始化地图 const initGraph = async () => { let line = await readline(); [N, M] = line.split(' ').map(Number); graph = new Array(N).fill(0).map(() => new Array(M).fill(0)) for (let i = 0; i < N; i++) { line = await readline() line = line.split(' ').map(Number) for (let j = 0; j < M; j++) { graph[i][j] = line[j] } } } /** * @description: 从(x,y)开始深度优先遍历地图 * @param {*} graph 地图 * @param {*} x 开始搜索节点的下标 * @param {*} y 开始搜索节点的下标 * @return {*} */ const dfs = (graph, x, y) => { if(graph[x][y] === 0) return graph[x][y] = 0 // 标记为海洋 for (let i = 0; i < 4; i++) { let nextx = x + dir[i][0] let nexty = y + dir[i][1] if (nextx < 0 || nextx >= N || nexty < 0 || nexty >= M) continue dfs(graph, nextx, nexty) } } (async function () { // 读取输入,初始化地图 await initGraph() // 遍历地图左右两边 for (let i = 0; i < N; i++) { if (graph[i][0] === 1) dfs(graph, i, 0) if (graph[i][M - 1] === 1) dfs(graph, i, M - 1) } // 遍历地图上下两边 for (let j = 0; j < M; j++) { if (graph[0][j] === 1) dfs(graph, 0, j) if (graph[N - 1][j] === 1) dfs(graph, N - 1, j) } count = 0 // 统计孤岛的总面积 for (let i = 0; i < N; i++) { for (let j = 0; j < M; j++) { if (graph[i][j] === 1) count++ } } console.log(count); })() ``` #### 广搜版 ```javascript const r1 = require('readline').createInterface({ input: process.stdin }); // 创建readline接口 let iter = r1[Symbol.asyncIterator](); // 创建异步迭代器 const readline = async () => (await iter.next()).value; let graph // 地图 let N, M // 地图大小 let count = 0 // 孤岛的总面积 const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]] //方向 // 读取输入,初始化地图 const initGraph = async () => { let line = await readline(); [N, M] = line.split(' ').map(Number); graph = new Array(N).fill(0).map(() => new Array(M).fill(0)) for (let i = 0; i < N; i++) { line = await readline() line = line.split(' ').map(Number) for (let j = 0; j < M; j++) { graph[i][j] = line[j] } } } /** * @description: 从(x,y)开始广度优先遍历地图 * @param {*} graph 地图 * @param {*} x 开始搜索节点的下标 * @param {*} y 开始搜索节点的下标 * @return {*} */ const bfs = (graph, x, y) => { let queue = [] queue.push([x, y]) graph[x][y] = 0 // 只要加入队列,立刻标记 while (queue.length) { let [xx, yy] = queue.shift() for (let i = 0; i < 4; i++) { let nextx = xx + dir[i][0] let nexty = yy + dir[i][1] if (nextx < 0 || nextx >= N || nexty < 0 || nexty >= M) continue if (graph[nextx][nexty] === 1) { queue.push([nextx, nexty]) graph[nextx][nexty] = 0 // 只要加入队列,立刻标记 } } } } (async function () { // 读取输入,初始化地图 await initGraph() // 遍历地图左右两边 for (let i = 0; i < N; i++) { if (graph[i][0] === 1) bfs(graph, i, 0) if (graph[i][M - 1] === 1) bfs(graph, i, M - 1) } // 遍历地图上下两边 for (let j = 0; j < M; j++) { if (graph[0][j] === 1) bfs(graph, 0, j) if (graph[N - 1][j] === 1) bfs(graph, N - 1, j) } count = 0 // 统计孤岛的总面积 for (let i = 0; i < N; i++) { for (let j = 0; j < M; j++) { if (graph[i][j] === 1) count++ } } console.log(count); })() ``` ### TypeScript ### PhP ### Swift ### Scala ### C# ### Dart ### C