
<p align="center"><strong><a href="./qita/join.md">参与本项目</a>，贡献其他语言版本的代码，拥抱开源，让更多学习算法的小伙伴们受益！</strong></p>

# 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。

## 思路 

本题使用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 <iostream>
#include <vector>
using namespace std;
int dir[4][2] = {-1, 0, 0, -1, 1, 0, 0, 1}; // 保存四个方向
void dfs(vector<vector<int>>& 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<vector<int>> grid(n, vector<int>(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 <iostream>
#include <vector>
#include <queue>
using namespace std;
int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 四个方向
void bfs(vector<vector<int>>& grid, int x, int y) {
    queue<pair<int, int>> que;
    que.push({x, y});
    grid[x][y] = 0; // 只要加入队列，立刻标记
    while(!que.empty()) {
        pair<int ,int> 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<vector<int>> grid(n, vector<int>(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<int[]> 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

<div align="center"><a href="https://www.nowcoder.com/link/wx_sqlcarl199" target="_blank"><img src="https://code-thinking-1253855093.file.myqcloud.com/pics/20220416223343.png" width="1000"/></a></div>
