【算法打卡day4 | 2026-02-09 周一 | 算法: BFS and BFS】5_卡码网101_孤岛的总面积 | 6_卡码网102_沉没孤岛

- 第 164 篇 -
Date: 2026 - 02- 09 (周一)
Author: 郑龙浩(仟墨)

2026-02-09 周一 | 算法打卡day4

文章目录

5_卡码网101_孤岛的总面积

使用DFS或者BFS都可以做出这类题目

题目描述

给定一个由 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

我的代码

我使用了3中做法,DFS两个,BFS一个

cpp 复制代码
// Date: 2026-02-09 Author:郑龙浩

// 5_卡码网101_孤岛的总面积

// 题目要求计算"孤岛"的总面积

// 方法1:DFS 方法2: BFS

  

// 思路:

// 孤岛定义:位于矩阵内部且不与边缘接触的陆地组成的岛屿

// 解题步骤:

// 1. 首先,处理所有与边缘相连的陆地:

//    - 遍历矩阵的四条边(上、下、左、右)

//    - 对边界上的每个陆地(值为1的点),启动DFS/BFS

//    - 将这些与边缘相连的陆地全部标记为已访问,但不计入总面积

//    - 也可以选择将这些陆地直接"沉没"为海洋(赋值为0)

//

// 2. 然后,计算剩余陆地的总面积:

//    - 再次遍历整个矩阵(现在只考虑内部陆地)

//    - 对每个未访问的陆地,启动DFS/BFS计算其面积

//    - 累加所有内部岛屿的面积

//

// 3. 输出总面积

//

// 关键点:

// - 需要两次遍历:第一次处理边缘连接,第二次计算内部面积

// - 或者可以使用标记法,不修改原矩阵,用visited数组记录

  

// 用时:

#include "bits/stdc++.h"

using namespace std;

  

int direction[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};

int S = 0;

  

// DFS作用:深搜陆地,且将搜索到的陆地变为海洋

// 我理解的显性与隐性DFS的最基本的区别:(有助于我理解)

// 显性:确定传给dfs函数的坐标是合格的,进入后无需判断(x, y)是否合格

// 隐性:不确定传给dfs函数的坐标是合格的,进入后需判断(x, y)是否合格

  

// 显性:让dfs函数下一个搜索的坐标(nextX, nextY)周围的陆地时,不判断其坐标是否合格,而是让其进入下一层递归再判断(也就是函数开头判断)

// 隐性:只有合规的坐标(nextX, nextY),才会让dfs函数搜索周围的陆地,而这样就可以保证传给dfs的坐标,一定是个合规的陆地,也就无需对传入dfs的坐标(x, y)进行判断是否合规了

  
  

// 法1.1 隐性的递归终止条件

void dfs1(vector <vector <int>>& grid, int x, int y) {

    int height = grid.size();

    int width = grid[0].size();

    grid[x][y] = 0;

  

    int nextX, nextY;

    for (int i = 0; i < 4; i++) {

        nextX = x + direction[i][0];

        nextY = y + direction[i][1];

        // 只要下一个搜索的是  非越界的 && 陆地 就继续以(nextX, nextY) 为中心搜索陆地

        if (nextX >= 0 && nextX < height && nextY >= 0 && nextY < width && grid[nextX][nextY] == 1) {

            // grid[nextX][nextY] = 0;

            dfs1(grid, nextX, nextY);

  

        }

    }

}

  

// 法1.2 显性递归终止条件(其实就相当于把循环中的条件提到了函数开头)

  

void dfs2(vector <vector <int>>& grid, int x, int y) {

    int height = grid.size();

    int width = grid[0].size();

    // 如果(x, y) 越界 && 海洋,就return

    if (x < 0 || x >= height || y < 0 || y >= width || grid[x][y] == 0) {

        return;

    }

  

    grid[x][y] = 0; // 只有(x, y) 没越界 && 是陆地,才转海洋

  
  

    int nextX, nextY;

    for (int i = 0; i < 4; i++) {

        nextX = x + direction[i][0];

        nextY = y + direction[i][1];

        dfs2(grid, nextX, nextY);

    }

}

  

// 法2

void bfs(vector <vector <int>>& grid, int x, int y) {

    if (grid[x][y] == 0) { // 如果传过来的参数是海洋,则直接return,不搜索四周的坐标

        return;

    } else {

        grid[x][y] = 0;

    }

    int height = grid.size();

    int width = grid[0].size();

  

    queue <pair <int, int>> que; // 存储"待访问"的坐标

    que.push({x, y});

    int nextX, nextY;

  

    while (!que.empty()) {

        // 首先先将每次的中心坐标取出

        pair <int, int> cur = que.front();

        // 取出就是访问过,变为海洋

        que.pop();

        // 查找中心坐标四周的坐标,如果下一个坐标是否条件的,就将坐标push到que中,以待未来取出且作为中心坐标查找周围坐标

        for (int i = 0; i < 4; i++) {

            nextX = cur.first + direction[i][0];

            nextY = cur.second + direction[i][1];

            if (nextX >= 0 && nextX < height && nextY >= 0 && nextY < width && grid[nextX][nextY] == 1) {

                // 如果符合条件,也是访问过,变为海洋

                grid[nextX][nextY] = 0;

                que.push({nextX, nextY});

            }

        }

    }

}

  

int main(void) {

    ios::sync_with_stdio(0);

    cin.tie(0); cout.tie(0);

  

     return 0;

}

6_卡码网102_沉没孤岛

BFS 和 DFS两种 的做法

和101的做法类似,本质上没什么区别

**题目描述

给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿指的是由水平或垂直方向上相邻的陆地单元格组成的区域,且完全被水域单元格包围。孤岛是那些位于矩阵内部、所有单元格都不接触边缘的岛屿。

现在你需要将所有孤岛"沉没",即将孤岛中的所有陆地单元格(1)转变为水域单元格(0)。

输入描述

第一行包含两个整数 N, M,表示矩阵的行数和列数。

之后 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。

输出描述

输出将孤岛"沉没"之后的岛屿矩阵。 注意:每个元素后面都有一个空格

输入示例

复制代码
4 5
1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1

输出示例

复制代码
1 1 0 0 0
1 1 0 0 0
0 0 0 0 0
0 0 0 1 1
cpp 复制代码
// Date: 2026-02-09 Author:郑龙浩

// 6_卡码网102_沉没孤岛_BFSDFS

// 方法1:DFS 方法2: BFS

  

// 思路:

// 孤岛定义:位于矩阵内部且不与边缘接触的陆地组成的岛屿

// 和 5_卡码网101_孤岛的总面积 的做法类似,只不过这次边缘岛屿标记为了2

// 1 表示内陆,2 表示边缘陆地,0 表示海洋

  

// 用时:

#include "bits/stdc++.h"

using namespace std;

  

int direction[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};

int S = 0;

  

// DFS作用:深搜陆地,且将搜索到的陆地变为海洋

  

// 法1.1 隐性的递归终止条件

void dfs1(vector <vector <int>>& grid, int x, int y) {

    int height = grid.size();

    int width = grid[0].size();

    grid[x][y] = 2;

  

    int nextX, nextY;

    for (int i = 0; i < 4; i++) {

        nextX = x + direction[i][0];

        nextY = y + direction[i][1];

        // 只要下一个搜索的是  非越界的 && 陆地 就继续以(nextX, nextY) 为中心搜索陆地

        if (nextX >= 0 && nextX < height && nextY >= 0 && nextY < width && grid[nextX][nextY] == 1) {

            // grid[nextX][nextY] = 0;

            dfs1(grid, nextX, nextY);

  

        }

    }

}

  

// 法1.2 显性递归终止条件(其实就相当于把循环中的条件提到了函数开头)

  

void dfs2(vector <vector <int>>& grid, int x, int y) {

    int height = grid.size();

    int width = grid[0].size();

    // 如果(x, y) 越界 && 海洋,就return

    if (x < 0 || x >= height || y < 0 || y >= width || grid[x][y] == 0) {

        return;

    }

  

    grid[x][y] = 2; // 只有(x, y) 没越界 && 是陆地,才标记为2

  
  

    int nextX, nextY;

    for (int i = 0; i < 4; i++) {

        nextX = x + direction[i][0];

        nextY = y + direction[i][1];

        dfs2(grid, nextX, nextY);

    }

}

  

// 法2

void bfs(vector <vector <int>>& grid, int x, int y) {

    if (grid[x][y] == 0) { // 如果传过来的参数是海洋,则直接return,不搜索四周的坐标

        return;

    } else {

        grid[x][y] = 2;

    }

    int height = grid.size();

    int width = grid[0].size();

  

    queue <pair <int, int>> que; // 存储"待访问"的坐标

    que.push({x, y});

    int nextX, nextY;

  

    while (!que.empty()) {

        // 首先先将每次的中心坐标取出

        pair <int, int> cur = que.front();

        // 取出就是访问过,变为海洋

        que.pop();

        // 查找中心坐标四周的坐标,如果下一个坐标是否条件的,就将坐标push到que中,以待未来取出且作为中心坐标查找周围坐标

        for (int i = 0; i < 4; i++) {

            nextX = cur.first + direction[i][0];

            nextY = cur.second + direction[i][1];

            if (nextX >= 0 && nextX < height && nextY >= 0 && nextY < width && grid[nextX][nextY] == 1) {

                // 如果符合条件,也是访问过,变为海洋

                grid[nextX][nextY] = 2;

                que.push({nextX, nextY});

            }

        }

    }

}

  

int main(void) {

    ios::sync_with_stdio(0);

    cin.tie(0); cout.tie(0);

  

    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];

        }

    }

  

    // 将与左右两列陆地连接的陆地标记为2

    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);

    }  

    // 将与上下两行陆地连接的陆地标记为2

    for (int i = 0; i < M; i++) {

        if (grid[0][i] == 1) bfs(grid, 0, i);

        if (grid[N - 1][i] == 1) bfs(grid, N - 1, i);

    }

    // 所有边缘的陆地都标记为了2,所以内陆为1,所以标记为1的陆地都输出为0

    for (int i = 0; i < N; i ++) {

        for (int j = 0; j < M; j++) {

            if (grid[i][j] == 1)

                cout << 0 << ' ';

            else if (grid[i][j] == 2)

                cout << 1 << ' ';

            else

                cout << 0 << ' ';

        }

        cout << '\n';

    }

     return 0;

}
相关推荐
寻寻觅觅☆9 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
偷吃的耗子10 小时前
【CNN算法理解】:三、AlexNet 训练模块(附代码)
深度学习·算法·cnn
化学在逃硬闯CS10 小时前
Leetcode1382. 将二叉搜索树变平衡
数据结构·算法
ceclar12311 小时前
C++使用format
开发语言·c++·算法
Gofarlic_OMS11 小时前
科学计算领域MATLAB许可证管理工具对比推荐
运维·开发语言·算法·matlab·自动化
夏鹏今天学习了吗11 小时前
【LeetCode热题100(100/100)】数据流的中位数
算法·leetcode·职场和发展
忙什么果12 小时前
上位机、下位机、FPGA、算法放在哪层合适?
算法·fpga开发
董董灿是个攻城狮12 小时前
AI 视觉连载4:YUV 的图像表示
算法
ArturiaZ13 小时前
【day24】
c++·算法·图论
大江东去浪淘尽千古风流人物13 小时前
【SLAM】Hydra-Foundations 层次化空间感知:机器人如何像人类一样理解3D环境
深度学习·算法·3d·机器人·概率论·slam