代码随想录算法训练营第45天|101. 孤岛的总面积、102. 沉没孤岛、103. 水流问题、104.建造最大岛屿

卡玛网101

2025-03-20 20:24:48 星期四

今天的题真是上强度了哈😆

题目描述:卡玛网101
文档讲解:代码随想录(programmercarl)101. 孤岛的总面积

孤岛是那些位于矩阵内部、所有单元格都不接触边缘的岛屿。

梳理

本题没思路,看了一下k哥的讲解,就是直接遍历地图周围四个边

靠地图四边的陆地,通过深搜或者广搜来进行标记,将所有靠近地图边缘的陆地变成0,也就是海洋

那么此时图中的就只有海洋和孤岛了,那么最后再遍历一遍地图,统计所有孤岛的数量即可

卡玛网测试

广搜版本

点击查看代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
int sum = 0;

void bfs(vector<vector<int>> &grid, vector<vector<int>> &visited, int x, int y) {
    queue<pair<int, int>> que;
    que.push({x, y});
    grid[x][y] = 0;
    visited[x][y] = 1;
    while (!que.empty()) {
        pair<int, int> cur = que.front();
        que.pop();
        for (int i = 0; i < 4; i++) {
            int nextx = cur.first + dir[i][0];
            int nexty = cur.second + dir[i][1];
            if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;
            if (grid[nextx][nexty] == 1 && visited[nextx][nexty] == 0) {
                que.push({nextx, nexty});
                visited[nextx][nexty] = 1;
                grid[nextx][nexty] = 0;
            }
        }
    }
}


int main() {
    int N, M;
    int count = 0;
    cin >> N >> M;
    vector<vector<int>> grid(N, vector<int>(M, 0));
    vector<vector<int>> visited(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 j = 0; j < M - 1; j++) {
        if (grid[0][j] == 1 && visited[0][j] == 0) {
            bfs(grid, visited, 0, j);
        }
    }

    for (int i = 0; i < N - 1; i++) {
        if (grid[i][M - 1] == 1 && visited[i][M - 1] == 0) {
            bfs(grid, visited, i, M - 1);
        }
    }

    for (int j = M - 1; j > 0; j--) {
        if (grid[N - 1][j] == 1 && visited[N - 1][j] == 0) {
            bfs(grid, visited, N - 1, j);
        }
    }

    for (int i = N - 1; i > 0; i--) {
        if (grid[i][0] == 1 && visited[i][0] == 0) {
            bfs(grid, visited, i, 0);
        }
    }
    
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            // cout << grid[i]
            if (grid[i][j] == 1) count++;
        }
    }
    cout << count << endl;
}

深搜版本

点击查看代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
int sum = 0;

void dfs(vector<vector<int>> &grid, vector<vector<int>> &visited, int x, int y) {
    if (grid[x][y] == 0 || visited[x][y] == 1) return;
    visited[x][y] = 1;
    grid[x][y] = 0;
    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] == 1 && visited[nextx][nexty] == 0){
            dfs(grid, visited, nextx, nexty);
        }
    }
}


int main() {
    int N, M;
    int count = 0;
    cin >> N >> M;
    vector<vector<int>> grid(N, vector<int>(M, 0));
    vector<vector<int>> visited(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 j = 0; j < M - 1; j++) {
        if (grid[0][j] == 1 && visited[0][j] == 0) {
            dfs(grid, visited, 0, j);
        }
    }

    for (int i = 0; i < N - 1; i++) {
        if (grid[i][M - 1] == 1 && visited[i][M - 1] == 0) {
            dfs(grid, visited, i, M - 1);
        }
    }

    for (int j = M - 1; j > 0; j--) {
        if (grid[N - 1][j] == 1 && visited[N - 1][j] == 0) {
            dfs(grid, visited, N - 1, j);
        }
    }

    for (int i = N - 1; i > 0; i--) {
        if (grid[i][0] == 1 && visited[i][0] == 0) {
            dfs(grid, visited, i, 0);
        }
    }
    
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            // cout << grid[i]
            if (grid[i][j] == 1) count++;
        }
    }
    cout << count << endl;
}

卡玛网102

题目描述:卡玛网102
文档讲解:代码随想录(programmercarl)102. 沉没孤岛

梳理

再上一题的基础上,在主函数中做一个判断,分情况讨论一下就行

卡玛网测试

广搜版本

点击查看代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
int sum = 0;

void bfs(vector<vector<int>> &grid, vector<vector<int>> &visited, int x, int y) {
    queue<pair<int, int>> que;
    que.push({x, y});
    grid[x][y] += 1;
    visited[x][y] = 1;
    while (!que.empty()) {
        pair<int, int> cur = que.front();
        que.pop();
        for (int i = 0; i < 4; i++) {
            int nextx = cur.first + dir[i][0];
            int nexty = cur.second + dir[i][1];
            if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;
            if (grid[nextx][nexty] == 1 && visited[nextx][nexty] == 0) {
                que.push({nextx, nexty});
                visited[nextx][nexty] = 1;
                grid[nextx][nexty] += 1;
            }
        }
    }
}


int main() {
    int N, M;
    int count = 0;
    cin >> N >> M;
    vector<vector<int>> grid(N, vector<int>(M, 0));
    vector<vector<int>> visited(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 j = 0; j < M - 1; j++) {
        if (grid[0][j] == 1 && visited[0][j] == 0) {
            bfs(grid, visited, 0, j);
        }
    }

    for (int i = 0; i < N - 1; i++) {
        if (grid[i][M - 1] == 1 && visited[i][M - 1] == 0) {
            bfs(grid, visited, i, M - 1);
        }
    }

    for (int j = M - 1; j > 0; j--) {
        if (grid[N - 1][j] == 1 && visited[N - 1][j] == 0) {
            bfs(grid, visited, N - 1, j);
        }
    }

    for (int i = N - 1; i > 0; i--) {
        if (grid[i][0] == 1 && visited[i][0] == 0) {
            bfs(grid, visited, i, 0);
        }
    }
    
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (grid[i][j] == 2) {
                grid[i][j] -= 1;
            } else if (grid[i][j] == 1) {
                grid[i][j] -= 1;
            }
        }
    }
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cout << grid[i][j] << ' ';
        }
        cout << endl;
    }
}

深搜版本

点击查看代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
int sum = 0;

void dfs(vector<vector<int>> &grid, vector<vector<int>> &visited, int x, int y) {
    if (grid[x][y] == 0 || visited[x][y] == 1) return;
    visited[x][y] = 1;
    grid[x][y] += 1;
    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] == 1 && visited[nextx][nexty] == 0){
            dfs(grid, visited, nextx, nexty);
        }
    }
}


int main() {
    int N, M;
    cin >> N >> M;
    vector<vector<int>> grid(N, vector<int>(M, 0));
    vector<vector<int>> visited(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 j = 0; j < M - 1; j++) {
        if (grid[0][j] == 1 && visited[0][j] == 0) {
            dfs(grid, visited, 0, j);
        }
    }

    for (int i = 0; i < N - 1; i++) {
        if (grid[i][M - 1] == 1 && visited[i][M - 1] == 0) {
            dfs(grid, visited, i, M - 1);
        }
    }

    for (int j = M - 1; j > 0; j--) {
        if (grid[N - 1][j] == 1 && visited[N - 1][j] == 0) {
            dfs(grid, visited, N - 1, j);
        }
    }

    for (int i = N - 1; i > 0; i--) {
        if (grid[i][0] == 1 && visited[i][0] == 0) {
            dfs(grid, visited, i, 0);
        }
    }
    
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (grid[i][j] == 2) {
                grid[i][j] -= 1;
            } else if (grid[i][j] == 1) {
                grid[i][j] -= 1;
            }
        }
    }

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cout << grid[i][j] << ' ';
        }
        cout << endl;
    }
    
}

卡码网103

题目描述:力扣103
文档讲解:代码随想录(programmarcarl)103. 水流问题

这个题直接给我看不会了。真的感觉好复杂。

初步梳理

  1. 该题的最终目的就是求出那些可以同时到达两个边界的所有的点。首先就是遍历图中每一个结点

  2. 每一个结点用深缩或者广搜,将其每一个可达的结点(也就是从高到低)的visited数组进行标记为1(注意visited数组这里不再表示有没有访问过此节点,而是表示可不可达

  3. 之后遍历每一组边界的分别两条边,对visited数组进行检查,用visited数组来对isFirst和isSecond进行标记。那么最后如果两个isFirst和isSecond都被标记过了。那么就表示该点出发可达同时两个边界,就将该点进行一个存储

  4. 最后将所有的点进行打印输出

思路优化版本

优化版本就是从四条边界出发,和之前的101和102一样,这样从低到高进行遍历,同时会新建两个数组firstBoard和secondBoard对可达的情况(0或1)进行存储,最后遍历如果该元素在两个数组中都是1,那么就将其输出

卡玛网测试

无论是优化还是没有优化过的版本,都需要注意一点就是

较高或等高的地点流向较低或等高并且相邻(上下左右方向)的地点。

就是等高也是可以流动的!

第一种版本

就是需要注意的一点就是每次在调用isReached函数的时候再新建visited数组,再用深搜或者广搜。如果在主函数中直接新建一个visited数组,并且加上引用传递,那么最后的结果会多很多无关的结果。

但是这么写并没有超出时间限制🧐

代码真的好长

点击查看代码
#include<iostream>
#include<vector>
using namespace std;
int N, M;
int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};

void dfs(vector<vector<int>> &grid, vector<vector<int>> &visited, int x, int y) {
    if (visited[x][y] == 1) return;
    visited[x][y] = 1;
    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[x][y] > grid[nextx][nexty]) {
            dfs(grid, visited, nextx, nexty);
        }
    }
}

bool isReached(vector<vector<int>> &grid, int x, int y) {
    vector<vector<int>> visited(N, vector<int>(M, 0));
    bool isFisrt = false;
    bool isSecond = false;
    // 对所有结点进行一个标记
    dfs(grid, visited, x, y);


    // 对两组边界进行可达判断

    // 首先是第一组边界的左
    for (int i = 0; i < N; i++) {
        if (visited[i][0] == 1) {
            isFisrt = true;
        }
    }
    
    // 第一组边界的上
    for (int j = 0; j < M; j++) {
        if (visited[0][j] == 1) {
            isFisrt = true;
        }
    }

    // 第二组边界的右
    for (int i = 0; i < N; i++) {
        if (visited[i][M - 1] == 1) {
            isSecond = true;
        }
    }

    // 第二组边界的下
    for (int j = 0; j < M; j++) {
        if (visited[N - 1][j] == 1) {
            isSecond = true;
        }
    }

    if (isFisrt && isSecond) return true;
    return false;
}


int main() {
    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++) {
            bool flag =  isReached(grid, i, j);
            if (flag) {
                cout << i << ' ' << j << endl;
            }
        }
    }
}

优化版本

点击查看代码
#include<iostream>
#include<vector>
using namespace std;
int N, M;
int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};

void dfs(vector<vector<int>> &grid, vector<vector<int>> &visited, int x, int y) {
    if (visited[x][y] == 1) return;
    visited[x][y] = 1;
    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[x][y] <= grid[nextx][nexty]) {
            dfs(grid, visited, nextx, nexty);
        }
    }
}


int main() {
    cin >> N >> M;
    vector<vector<int>> grid(N, vector<int>(M, 0));
    vector<vector<int>> firstBoard(N, vector<int>(M, 0));
    vector<vector<int>> secondBoard(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++) {
        dfs(grid, firstBoard, i, 0);
    }
    
    // 第一组边界的上
    for (int j = 0; j < M; j++) {
        dfs(grid, firstBoard, 0, j);
    }

    // 第二组边界的右
    for (int i = 0; i < N; i++) {
        dfs(grid, secondBoard, i, M - 1);
    }

    // 第二组边界的下
    for (int j = 0; j < M; j++) {
        dfs(grid, secondBoard, N - 1, j);
    }

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (firstBoard[i][j] == 1 && secondBoard[i][j] == 1) {
                cout << i << ' ' << j << endl;
            }
        }
    }
}

卡玛网104

题目描述:卡玛网104
文档讲解:代码随想录(progarmmarcarl)104.建造最大岛屿

又是一道直接给我看傻了的题🤐

梳理

  1. 首先是需要在原始的岛屿中进行面积统计,就是如果grid是1并且没有被访问过,那么就要进行深搜或者广搜,来对相邻岛屿进行计数,从而count++。
  1. 接着要区分开每一个岛屿,所以用了mark进行标记。具体在处理的时候就是dfs或者bfs中会对每个grid[x][y]进行修改,使得每个岛屿都用各自的编号。同时这里还用了一个gridNum,是一个unordered_map,对每一个mark对应的value面积进行存储。
  1. 遍历每一个0的方格,并统计其相邻岛屿面积,最后取一个最大值。我感觉这步不太好想,其实这里就是和上面用mark修改grid的值紧密相连的,也要用dir的四个方向,取该为0的方格的上下左右四个方向,之后对四个方向的单元格的值进行查询,如果是2,那么访问gridNum面积就是7,如果是3, 那么访问gridNum面积就是3,之后进行加和。那么当所有的为0的方格遍历完毕的时候,就能统计出来岛屿面积的最大值

    同时,这步要引入一个unordered_set类型的visitedGrid表示不能把已经添加过的岛屿再添加进来,比如该方格的两条边同时和一个岛屿接壤,那么只能添加一次

  1. 如果整个地图都是海洋,没有岛屿,那么就直接返回全面积,用isAllGrid表示true

卡玛网测试

终于过啦!需要注意的是

就是在第三步中,一定记得把visitedGrid在每次访问新的0方格时进行清空,要不然就可能会少添加一些岛屿。导致最终的面积变小

这个题好难😣

点击查看代码
#include<iostream>
#include<vector>
#include<unordered_map>
#include<unordered_set>
using namespace std;
int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
int count = 0;

void dfs(vector<vector<int>> &grid, vector<vector<int>> &visited, int x, int y, int &mark) {
    if (visited[x][y] == 1) return;
    count++;
    grid[x][y] = mark;
    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] == 1 && visited[nextx][nexty] == 0) {
            dfs(grid, visited, nextx, nexty, mark);
        }
    }
}

int main() {
    int N, M;
    cin >> N >> M;
    vector<vector<int>> grid(N, vector<int>(M, 0));
    vector<vector<int>> visited(N, vector<int>(M, 0));
    // 图的存储
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++){
            cin >> grid[i][j];
        }
    }

    // 第二步,深搜,同时对各个岛屿的数值进行修改
    bool isAllGrid = true;
    unordered_map<int, int> gridNum;
    int mark = 2;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (grid[i][j] == 0) isAllGrid = false;
            // 表示访问了一个新的岛屿(不连通)
            if (grid[i][j] == 1 && visited[i][j] == 0) {
                count = 0;
                dfs(grid, visited, i, j, mark);
                gridNum[mark] = count;
                mark++;
            }
            
        }
    }

    // for (int i = 0; i < N; i++) {
    //     for (int j = 0; j < M; j++) {
    //         cout << grid[i][j] << ' ';
    //     }
    //     cout << endl;
    // }

    // cout << gridNum[4] << endl;

    if (isAllGrid) {
        cout << N * M << endl;
        return 0;
    }

    // 第三步,对海洋单元格进行访问,对四周的面积进行加和
    int allCount = 1;
    int result = 0;
    unordered_set<int> visitedGrid;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (grid[i][j] == 0) {
                for (int k = 0; k < 4; k++) {
                    int nearx = i + dir[k][0];
                    int neary = j + dir[k][1];
                    if (nearx < 0 || nearx >= grid.size() || neary < 0 || neary >= grid[0].size()) continue;
                    if (visitedGrid.count(grid[nearx][neary])) continue;
                    allCount += gridNum[grid[nearx][neary]];
                    visitedGrid.insert(grid[nearx][neary]);
                }
                result = max(allCount, result);
            }
            allCount = 1;
            visitedGrid.clear();
        }
    }
    cout << result << endl;
}
posted on 2025-03-20 20:26  bnbncch  阅读(45)  评论(0)    收藏  举报