代码随想录训练营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;
}

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

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

相关推荐
Ysjt | 深1 分钟前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++
ephemerals__7 分钟前
【c++丨STL】list模拟实现(附源码)
开发语言·c++·list
IT古董21 分钟前
【机器学习】机器学习中用到的高等数学知识-8. 图论 (Graph Theory)
人工智能·机器学习·图论
Microsoft Word22 分钟前
c++基础语法
开发语言·c++·算法
天才在此35 分钟前
汽车加油行驶问题-动态规划算法(已在洛谷AC)
算法·动态规划
一只小小汤圆1 小时前
opencascade源码学习之BRepOffsetAPI包 -BRepOffsetAPI_DraftAngle
c++·学习·opencascade
legend_jz1 小时前
【Linux】线程控制
linux·服务器·开发语言·c++·笔记·学习·学习方法
嘿BRE1 小时前
【C++】几个基本容器的模拟实现(string,vector,list,stack,queue,priority_queue)
c++
莫叫石榴姐1 小时前
数据科学与SQL:组距分组分析 | 区间分布问题
大数据·人工智能·sql·深度学习·算法·机器学习·数据挖掘
ö Constancy2 小时前
c++ 笔记
开发语言·c++