参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们受益!
# 101. 孤岛的总面积
卡码网:101. 孤岛的总面积 (opens new window)
题目描述
给定一个由 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
2
3
4
5
2
3
4
5
输出示例:
1
提示信息:
在矩阵中心部分的岛屿,因为没有任何一个单元格接触到矩阵边缘,所以该岛屿属于孤岛,总面积为 1。
数据范围:
1 <= M, N <= 50。
# 思路
本题使用dfs,bfs,并查集都是可以的。
本题要求找到不靠边的陆地面积,那么我们只要从周边找到陆地然后 通过 dfs或者bfs 将周边靠陆地且相邻的陆地都变成海洋,然后再去重新遍历地图 统计此时还剩下的陆地就可以了。
如图,在遍历地图周围四个边,靠地图四边的陆地,都为绿色,
在遇到地图周边陆地的时候,将1都变为0,此时地图为这样:
然后我们再去遍历这个地图,遇到有陆地的地方,去采用深搜或者广搜,边统计所有陆地。
如果对深搜或者广搜不够了解,建议先看这里:深度优先搜索精讲,广度优先搜索精讲。
采用深度优先搜索的代码如下:
#include <iostream>
#include <vector>
using namespace std;
int dir[4][2] = {-1, 0, 0, -1, 1, 0, 0, 1}; // 保存四个方向
int count; // 统计符合题目要求的陆地空格数量
void dfs(vector<vector<int>>& grid, int x, int y) {
grid[x][y] = 0;
count++;
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);
}
count = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 1) dfs(grid, i, j);
}
}
cout << count << endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
采用广度优先搜索的代码如下:
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int count = 0;
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; // 只要加入队列,立刻标记
count++;
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});
count++;
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);
}
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);
}
}
cout << count << endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# 其他语言版本
# 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);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# Python
from collections import deque
# 处理输入
n, m = list(map(int, input().strip()))
g = []
for _ in range(n):
row = list(map(int, input().strip()))
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# 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)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# Rust
# 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);
})()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# 广搜版
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);
})()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# TypeScript
# PhP
# Swift
# Scala
# C#
# Dart
# C
← 7. 岛屿的最大面积 9. 沉没孤岛 →
@2021-2024 代码随想录 版权所有 粤ICP备19156078号