Studying-代码随想录训练营day51| 99.岛屿数量 深搜、99.岛屿数量 广搜、100.岛屿的最大面积

第51天,图论02,岛屿题型💪(ง •_•)ง,编程语言C++

目录

99.岛屿数量 深搜

99.岛屿数量 广搜 

100.岛屿的最大面积 

总结 


99.岛屿数量 深搜

文档讲解:手撕岛屿数量 深搜

题目:99. 岛屿数量 (kamacoder.com)

学习:本题首先要理解题意,明确岛屿划分的方法。岛屿是只能由水平方向和竖直方向上相邻的陆地连接形成的,也就是说斜角度连接是不算的,因此一个陆地只有四个向外扩展的方向。

本题的思路是遇到一个没有标记过的节点陆地,计数器就加一(岛屿数量加一),然后把这个节点周围相连的陆地都标记上(属于同一个岛屿)。

之后继续遍历图,如果遇到标记过的陆地,或者海洋就跳过,直到下一个没有标记过的陆地,也就是一个新的岛屿。

代码:十分要注意仔细书写,不要写错代码!!!

#include <iostream>
#include <vector>
using namespace std;

int dir[4][2] = {{0,1}, {1,0}, {-1, 0}, {0, -1}}; //四个方向(根据x,y来调整方向)
//1.确定返回值,及参数列表
void dfs(const vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y) { //dfs
    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; //越界
        //2.终止条件:只有复合条件才进入递归
        if(!visited[nextx][nexty] && grid[nextx][nexty] == 1) { //如果当前位置没有被标记且是陆地,这里注意该陆地是和我们找到的岛屿一起的
            //3.处理当前节点,单层递归逻辑
            visited[nextx][nexty] = true; //进行标记
            dfs(grid, visited, 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];
        }
    }
    vector<vector<bool>> visited(n, vector<bool>(m, false)); //标记地图上的点
    
    int result = 0; //记录岛屿数量
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            if(!visited[i][j] && grid[i][j] == 1) { //如果当前点没有被标记,且是陆地的情况下,我们认为找到了一个岛屿
                result++; //我们认为找到一个岛屿
                visited[i][j] == true; //进行标记
                dfs(grid, visited, i, j); //标记这片岛屿的所有陆地
            }
        }
    }
    cout << result << endl;
    return 0;
}

本题终止条件是写在了调用dfs的地方,如果遇到不合法的方向,直接不会去调用dfs。当然写在开头也是可以的,只不过会多一些不必要的递归。


99.岛屿数量 广搜 

文档讲解:手撕岛屿数量 广搜

题目:99. 岛屿数量 (kamacoder.com)

学习:上面我们采用了深搜的方式进行本题的求解。本题我们还可以采用广搜(广度优先搜索bfs)进行求解。

本题采用广度优先搜索方法,主要需要注意防止超时。对于广搜来说我们要注意:加入队列就代表走过了,就需要进行标记,而不是队列拿出来的时候,再进行标记。区别就在于,如果从队列拿出来的时候,再进行标记,会导致出现重复加入队列的情况。(如下图所示)

因此本题的代码为:

#include <iostream>
#include <queue>
#include <vector>
using namespace std;

int dir[4][2] = {{0,1}, {1,0}, {-1, 0}, {0, -1}}; //四个方向(根据x,y来调整方向)
//采用广度优先搜索的办法
void bfs(const vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y) { //bfs
    queue<pair<int, int>> que;
    que.push({x, y});
    visited[x][y] = true;
    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(!visited[nextx][nexty] && grid[nextx][nexty] == 1) { //与我们找到的岛屿连接在一起的陆地
                que.push({nextx, nexty});
                visited[nextx][nexty] = true;
            }
        }
    }
    
    
}

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)); //标记地图上的点
    
    int result = 0; //记录岛屿数量
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            if(!visited[i][j] && grid[i][j] == 1) { //如果当前点没有被标记,且是陆地的情况下,我们认为找到了一个岛屿
                result++; //我们认为找到一个岛屿
                bfs(grid, visited, i, j); //标记这片岛屿的所有陆地
            }
        }
    }
    cout << result << endl;
    return 0;
}

100.岛屿的最大面积 

文档讲解:手撕岛屿的最大面积

题目:100. 岛屿的最大面积 (kamacoder.com)

学习:本题实际上和上一题是一样的,只不过上一题要求求的是岛屿的数量,本题要求求的是岛屿的最大面积。采用dfs和bfs方法都可以,只需要增加一个count量,来记录每次找到的岛屿的面积即可。

代码:dfs

#include <iostream>
#include <vector>
using namespace std;
int count;
int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 四个方向
void dfs(vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y) {
    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 (!visited[nextx][nexty] && grid[nextx][nexty] == 1) { // 没有访问过的 同时 是陆地的
            visited[nextx][nexty] = true;
            count++; //因为是全局变量,会一直记录到下一个岛屿重置为1为止
            dfs(grid, visited, 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];
        }
    }
    vector<vector<bool>> visited(n, vector<bool>(m, false));
    int result = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (!visited[i][j] && grid[i][j] == 1) {
                count = 1;  // 找到一个新岛屿,重置计数值,重新从1开始计算
                visited[i][j] = true;
                dfs(grid, visited, i, j); // 将与其链接的陆地都标记上 true
                result = max(result, count);
            }
        }
    }
    cout << result << endl;

}

代码:bfs

class Solution {
private:
    int count;
    int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 四个方向
    void bfs(vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y) {
        queue<int> que;
        que.push(x);
        que.push(y);
        visited[x][y] = true; // 加入队列就意味节点是陆地可到达的点
        count++;
        while(!que.empty()) {
            int xx = que.front();que.pop();
            int yy = que.front();que.pop();
            for (int i = 0 ;i < 4; i++) {
                int nextx = xx + dir[i][0];
                int nexty = yy + dir[i][1];
                if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue; // 越界
                if (!visited[nextx][nexty] && grid[nextx][nexty] == 1) { // 节点没有被访问过且是陆地
                    visited[nextx][nexty] = true;
                    count++;
                    que.push(nextx);
                    que.push(nexty);
                }
            }
        }
    }

public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int n = grid.size(), m = grid[0].size();
        vector<vector<bool>> visited = vector<vector<bool>>(n, vector<bool>(m, false));
        int result = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (!visited[i][j] && grid[i][j] == 1) {
                    count = 0;
                    bfs(grid, visited, i, j); // 将与其链接的陆地都标记上 true
                    result = max(result, count);
                }
            }
        }
        return result;
    }
};

总结 

该两题是dfs和bfs最基础的题目,直接考察dfs和bfs的书写能力。相较于其他算法dfs和bfs的代码很多,要十分注意书写错误(书写错误带来的调debug的难度很高)。多加练习!!!加强书写!!!

  • 11
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值