代码随想录训练营Day 66|卡码网101.孤岛的总面积、102.沉没孤岛、103.水流问题、104.建造最大岛屿

1.孤岛的总面积

101. 孤岛的总面积 | 代码随想录

代码:(bfs广搜)

cpp 复制代码
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int dir[4][2] = {1,0,0,1,-1,0,0,-1};
int count;
void bfs(vector<vector<int>>&grid,int x,int y){
    queue<pair<int,int>> que;
    que.push({x,y});
    grid[x][y] = 0; // 这里用grid的元素变为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});
                grid[nextx][nexty] = 0;
                count++;
            }
        }
    }
}
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 = 1; i < n - 1; i++){
        for(int j = 1; j < m - 1; j++){
            if(grid[i][j] == 1) bfs(grid,i,j);
        }
    }
    // 输出
    cout << count << endl;
}

思路:基础题型,这次直接在grid表上进行标记。先把靠近陆地的岛屿都标为0。将用于统计面积的变量的count置为0。接下来就可以排除临近陆地的岛屿,只统计孤岛的数量了。

易错点:我又犯错了。先是忘记写命名空间了,然后又是在if判断里二维数组我只写了一个下标,最后是找边界找错了,我的循环变量i是在变的,我只要固定另一个下标为临界值就好了。不知道为什么我把i放到了边界的运算里(。。脑子糊了)

代码:(dfs 深搜)

cpp 复制代码
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int dir[4][2] = {1,0,0,1,-1,0,0,-1};
int count;
void bfs(vector<vector<int>>&grid,int x,int y){
    if(grid[x][y] == 0){
        return;
    }
    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;
        }
        bfs(grid,nextx,nexty);
    }
}
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 = 1; i < n - 1; i++){
        for(int j = 1; j < m - 1; j++){
            if(grid[i][j] == 1) bfs(grid,i,j);
        }
    }
    // 输出
    cout << count << endl;
}

思路:我的博客快做成个人错误大赏了。。。

这次的错误是 在进行下标是否非法的判断的时候,我又写错了。一定要注意边界条件啊,以后检查的时候就应该找这种判断语句好好看看。

2.沉没孤岛

102. 沉没孤岛 | 代码随想录

代码:(深搜dfs)

cpp 复制代码
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int dir[4][2] = {1,0,0,1,-1,0,0,-1};
int count;
void bfs(vector<vector<int>>&grid,int x,int y){
    if(grid[x][y] == 2||grid[x][y] == 0){
        return;
    }
    grid[x][y] = 2;
    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;
        }
        bfs(grid,nextx,nexty);
    }
}
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];
        }
    }
    // 处理
    // 将临近陆地的标为2 和 孤岛区分开
    vector<vector<bool>> visited(n,vector<bool>(m,false));
    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);
    }
    // 将孤岛沉没 将临近陆地的单元还原
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            if(grid[i][j] == 1) grid[i][j] = 0;
            if(grid[i][j] == 2) grid[i][j] = 1;
        }
    }
    // 输出
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            cout << grid[i][j] << " ";
        }
        cout << endl;
    }
}

思路:这里比较巧妙的就是因为临近陆地的岛屿比较好判断,所以将其标记为2,只要与孤岛区别开就好了。接下来,就是把1变为0,把2变为1,输出就好了

3.水流问题

103. 水流问题 | 代码随想录

代码: (深搜dfs)

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;
int dir[4][2] = {0,1,1,0,0,-1,-1,0};
void dfs(const vector<vector<int>> &grid,vector<vector<bool>> &visited,int x, int y){
    if(visited[x][y]) return;
    visited[x][y] = true;
    for(int i = 0; i < 4; i++){
        int nextx = x + dir[i][0];
        int nexty = y + dir[i][4];
        if(nextx < 0||nextx >= grid.size()||nexty < 0||nexty >= grid[0].size()){
            continue;
        }
        // 必须从低到高
        if(grid[nextx][nexty] < grid[x][y]) continue;
        dfs(grid,visited,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];
        }
    }
    // 处理
    vector<vector<bool>> firstBorder(n,vector<bool>(m,false));
    vector<vector<bool>> secondBorder(n,vector<bool>(m,false));
    for(int i = 0; i < n; i++){
        dfs(grid,firstBorder,i,0);
        dfs(grid,secondBorderBorder,i,m - 1);
    }
    for(int j = 0; j < m; j++){
        dfs(grid,firstBorder,0,j);
        dfs(grid,secondBorder,n - 1,j);
    }
    // 输出
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            if(firstBorder[i][j]&&secondBorder[i][j]){
                cout << i << j << endl;
            }
        }
    }
}

思路:这道题的优化很巧妙,因为从边界出发好判断,所以直接从边界出发,把边界可以到达的地方而且是递增的单元进行标记。上边界和下边界各用一套标记,当一个单元被标记两次时,就说明它时满足题意的。

易错点:我自己写了半天,忘记写最重要的 if(grid[nextx][nexty] < grid[x][y]) continue;了。

4.建造最大岛屿

104.建造最大岛屿 | 代码随想录

代码:

cpp 复制代码
#include <iostream>
#include <vector>
#include <unordered_set>
#include <unordered_map>
using namespace std;
int count;
int dir[4][2] = {0,1,1,0,0,-1,-1,0};
void dfs(vector<vector<int>>&grid,vector<vector<bool>>&visited,int x,int y,int mark){
    if(visited[x][y]||grid[x][y] == 0) return;
    visited[x][y] = true; // 标记已访问
    grid[x][y] = mark; // 每个岛屿都有对应的标签
    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;
        }
        dfs(grid,visited,nextx,nexty,mark);
    }
    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];
        }
    }
    // 处理
    vector<vector<bool>> visited(n,vector<bool>(m,false));
    unordered_map<int,int> gridNum;
    int mark = 2; // 记录岛屿的编号
    bool isAllGrid = true; // 记录整个地图是否都是陆地(如果是,就没法添加陆地了)
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            if(grid[i][j] == 0) isAllGrid = false;
            if(!visited[i][j] && grid[i][j] == 1){
                count = 0;
                dfs(grid,visited,i,j,mark);
                gridNum[mark] = count; // 记录每一个岛屿的面积
                mark++;
            }
        }
    }
    if(isAllGrid == true) {
        cout << n*m << endl;
        return 0;
    }
    // 根据所填陆地,计算周边岛屿面积之和
    int result = 0;
    unordered_set<int> visitedGrid; // 标记访问过的岛屿
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            count = 1; // 记录连接后的岛屿数量
            visitedGrid.clear();
            if(grid[i][j] == 0){
                for(int k = 0; k < 4; k++){
                    int nexti = i + dir[k][0];
                    int nextj = j + dir[k][1];
                    if(nexti < 0||nexti >= grid.size()||nextj < 0||nextj >= grid[0].size()){
                        continue;
                    }
                    if(visitedGrid.count(grid[nexti][nextj])) continue; // 添加过的岛屿不要重复添加
                    count += gridNum[grid[nexti][nextj]];
                    visitedGrid.insert(grid[nexti][nextj]);
                }
            }
            result = max(result,count);
        }
    }
    cout << result << endl;
}

思路:这道题是先计算各个岛屿的面积,然后遍历每一块海域,将这块添加的单元与其临近的岛屿面积进行相加求和,保存里面的最大值。

这道题真的是错死我了。。。这个涉及到很多细节,比如要考虑全是陆地的情况,要将每个岛屿进行面积和标号的映射,要在计算连接后的总面积的时候,将统计过的岛屿进行标记。。。我真的,太痛了。

相关推荐
九圣残炎6 分钟前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
lulu_gh_yu12 分钟前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
丫头,冲鸭!!!31 分钟前
B树(B-Tree)和B+树(B+ Tree)
笔记·算法
Re.不晚35 分钟前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
ULTRA??44 分钟前
C加加中的结构化绑定(解包,折叠展开)
开发语言·c++
凌云行者1 小时前
OpenGL入门005——使用Shader类管理着色器
c++·cmake·opengl
凌云行者1 小时前
OpenGL入门006——着色器在纹理混合中的应用
c++·cmake·opengl
为什么这亚子2 小时前
九、Go语言快速入门之map
运维·开发语言·后端·算法·云原生·golang·云计算
2 小时前
开源竞争-数据驱动成长-11/05-大专生的思考
人工智能·笔记·学习·算法·机器学习
~yY…s<#>2 小时前
【刷题17】最小栈、栈的压入弹出、逆波兰表达式
c语言·数据结构·c++·算法·leetcode