【算法打卡day6 | 2026-02-11 周三 | 算法: BFS and BFS】| 8_卡码网104_建造最大岛屿 | 9_卡码网106_海岸线计算

- 第 166 篇 -
Date: 2026 - 02- 11 | 周三
Author: 郑龙浩(仟墨)

2026-02-11 周三 | 算法打卡day6

文章目录

8_卡码网104_建造最大岛屿

题目描述

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

输出示例

复制代码
6

提示信息

数据范围:

1 <= M, N <= 50。

cpp 复制代码
// Date: 2026-02-11 周三 Author:郑龙浩

// 8_卡码网104_建造最大岛屿

// 用时:2 h 11 min

  
  

// 大概描述的话就是:

// - 使用dfs/bfs搜索岛屿,且对每个岛屿做不同的编号mark的标记,这个编号是直接写到了grid原数组中的

// - 然后用unordered_map<int ,int> gridS;记录每个岛屿(即编号)的面积:循环便利所有的点,然后girdS[mark]++不断累加每个岛屿的面积

// - 然后遍历所有点,如果遇到了海洋,就然后查找「上下左右」四个方向的陆地,如果是陆地就取出其陆地编号,并利用gridS去查找对应陆地的面积,然后将面积加入到S中,以此类推,去判断四个方向,然后如果是陆地就加上其面积

//     - 注意:添加过面积的岛屿不要重复添加

//     - 可能会存在比如,该海洋 左边 上边 的陆地是同一个岛屿的情况,此时左边 和 上边 如果都加到S中的话,同一个岛屿的面积就会计算两次

//     - 所以为了杜绝这种重复计算同一个岛屿的情况,在寻找四个方向的陆地的时候,需要判断四个方向的陆地是否是同一个岛屿,如果是的话,就只在S中加一次该岛屿的面积

//     - 写一个unordered_set <int> visited_mark 记录每个岛屿是否被添加过, 且每次遇到新海洋的时候都要记得clear一下vidited

  

// 1 遍历所有陆地,用DFS/BFS给每个岛屿编号,并计算每个岛屿的面积,存入grid_mark_S。

// 2 遍历所有海洋,计算如果把它变成陆地,加上周围不同岛屿的面积,得到可能的最大岛屿面积。

  

// 特殊情况,全是陆地

  

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

#include "bits/stdc++.h"

using namespace std;

  

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

  

// grid是矩阵,mark是岛屿的编号,cnt是岛屿面积,x, y 是现在的坐标

// 搜索 (x, y) 以及四周的坐标点

void dfs(vector <vector <int>>& grid, int mark, int& cnt, int x, int y) {

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

    // 如果在传入(x, y)之前有了这个判断,不写下面这一行判断也OK

    // 越界 || 海洋 || 编号过(访问过)的岛屿 就不需要搜索了,直接return

    if (x < 0 || x >= height || y < 0 || y >= width || grid[x][y] == 0 || grid[x][y] >= 2) // 为了保险加的,可以去掉这行

        return;

  

    cnt++; // (x, y)位置是新的陆地,该岛屿应该++

    grid[x][y] = mark; // mark 坐标 (x, y)

  

    int nextX, nextY;

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

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

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

        // 没越界 && 没标记(访问)过的岛屿 就使用dfs深搜周围

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

            dfs(grid, mark, cnt, nextX, nextY);

    }

}

  
  

// 我采用的是 入队就是访问

// 我原来的写的出队就是访问做法,如果少写了pop出来后判断是否访问过的话,就会出现重复访问多算面积的情况,

// 有可能会在入对的时候,入队多次,因为在入队的时候有可能那个坐标已经在que中了只是还没有循环到出队那一步

// 而且que中可能会加入多个相同的坐标, 需要多加一个pop后坐标判断

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

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

    // 越界 || 海洋 || 编号过(访问过)的岛屿 就不需要搜索了,直接return

    if (x < 0 || x >= height || y < 0 || y >= width || grid[x][y] == 0 || grid[x][y] >= 2) // 为了保险加的,可以去掉这行

        return;

  

    queue <pair <int, int>> que;

    que.push({x, y});

    grid[x][y] = mark;

    cnt++;

  

    while (!que.empty()) {

        auto cur = que.front();

        que.pop();

  

        int nextX, nextY;

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

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

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

  

            // 没越界 && 没标记(访问)过的岛屿 就加入que待搜队列

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

                que.push({nextX, nextY});

                cnt++;

                grid[nextX][nextY] = mark;

            }

        }

    }

  
  

}

  

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

  

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

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

            cin >> grid[i][j];

        }

    }

  

    // 1 对所有的岛屿进行编号操作 + 计算每个岛屿的面积

  

    unordered_map <int, int> grid_mark_S; // 岛屿编号 + 岛屿面积

    int mark = 2; // 从2开始标记,1是没访问过的陆地,>=2是访问且编号过的陆地,0是海洋

    int cnt = 1; // 岛屿面积

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

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

            if (grid[i][j] == 1) { // 如果为1则表示:是岛屿 且 没被编号

                cnt = 0; // 我写的dfs搜索的时候,是会搜索(x, y)以及四周,不只是只有四周的,所以面积为0就可以,会默认加上(x, y)的

                bfs(grid, mark, cnt, i, j); // 搜索 周围的陆地

                grid_mark_S[mark++] = cnt; // 填入面积

            }

        }

    }

  

    // 2 特殊情况,如果地图上全是陆地,没有海洋,第一个循环会给所有岛屿编号并计算面积

  

    // 第二个循环遍历所有海洋,但因为没有海洋(grid[i][j] != 0),所以Max会保持初始值0

    // 最后输出0,但正确答案应该是整个地图的面积(如果所有陆地是连通的)或最大岛屿的面积

    // 所以加了一个全是陆地判断,以免输出Max = 0

  

    // 解决方案:先把答案Max初始化为所有岛屿中的最大岛屿的面积,然后尝试每个海洋,如果填海能连接出更大的岛屿就更新答案

    int Max = 0;

    for (const auto& item : grid_mark_S) {

        Max = max(Max, item.second);

    }

  

    // 3 寻找海洋,尝试计算将海洋变成陆地后的面积

  

    int S = 1; // 面积,海洋变成陆地后的岛屿的面积

    unordered_set <int> visited_mark; // 记录已经算过面积的岛屿编号

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

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

            if (grid[i][j] == 0) { // 如果是海洋的话,就将其变为陆地然后加上周围的面积

                visited_mark.clear(); // 每次计算新坐标的时候,都要clear上次坐标周围的岛屿编号

                S = 1; // 将该海洋变为陆地,S = 1

                // 遍历该海洋周围的岛屿

                int nextX, nextY;

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

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

                    nextY = j + direction[k][1];

  

                    // 只有没越界,才可以访问(nextX, nextY)

                    if (nextX >= 0 && nextX < N && nextY >= 0 && nextY < M) {

                        // 遇到陆地 && 没访问过的岛屿 就 S += gridS[next_mark];

                        int next_mark = grid[nextX][nextY]; // 下一个坐标点的编号

                        if (next_mark >= 2 && visited_mark.find(next_mark) == visited_mark.end()) { // 如果没有,返回end

  

                            S += grid_mark_S[next_mark];

                            visited_mark.insert(next_mark); // 标记已访问该岛屿

                        }

                    }

  

                }

                // 保留最大面积

                if (Max < S) Max = S;

            }

        }

    }

  

    cout << Max;

    return 0;

}

9_卡码网106_海岸线计算

本题无需用dfs与bfs也能计算出来的,纯迭代做

cpp 复制代码
// Date: 2026-02-11 周三 Author:郑龙浩

// 9_卡码网106_海岸线计算

// 用时:5min

  

// 不需要使用DFSBFS也能做,直接遍历判断即可

// 遇到陆地时,就判断四周是否是海洋或者边界,有几个海洋或者陆地就+几

#include "bits/stdc++.h"

using namespace std;

  

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

  

int main(void) {

    ios::sync_with_stdio(0);

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

    int cnt = 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];

        }

    }

  

    // 计算海岸线

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

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

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

                // 计算每个陆地的海岸线是多少

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

                    int nextX = i + direction[k][0];

                    int nextY = j + direction[k][1];

  

                    // 若越界 或 遇到海洋 都算海洋,然后的都算海岸线

                    if (nextX < 0 || nextX >= N || nextY < 0 || nextY >= M || grid[nextX][nextY] == 0)

                        cnt++;

                }

            }

        }

    }

  

    cout << cnt;

    return 0;

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