代码随想录算法训练营第44天|99. 岛屿数量(深搜)、99. 岛屿数量(广搜)、100. 岛屿的最大面积

卡玛网99(深搜)

2025-03-19 18:30:52 星期三

题目描述:卡玛网99
文档讲解:代码随想录(programmercarl)99. 岛屿数量
视频讲解:图论:来用深搜解决一道题目,两种深搜写法,你掉坑了吗? | 卡码网:99.岛屿数量

代码随想录视频内容简记

首先是这道题用深搜的部分在哪里?就算在一片岛屿的时候,需要对这块岛屿进行一个搜索,就在这里。这里用深搜或者广搜都是可以的

梳理

  1. 将图进行存储

  2. 主函数进行图的遍历,以及深搜调用和输出打印

  3. 深搜部分

大致代码内容

  1. 这里用for循环遍历进行朴素存储,用grid = 1进行表示

  2. 新建一个visited数组,对图一行一行遍历,一旦有grid标记为1且visited不为1的元素,那么就进入深搜。同时定义一个全局变量dir数组表示四个方向

  3. 深搜主体采用深搜三部曲

    1. 确定递归函数及参数。void dfs (grid, visited, x, y),这里的x和y表示对当前结点的横纵坐标

    2. 确定递归的终止条件。if (grid[x][y] == 0 || visited[x][y] == 1) return;,之后要接一句就是visited[x][y] = 1,将当前结点标记为访问过

    3. 处理目前结点出发的路径。首先用for (int i = 0; i < 4; i++),接下来分别处理nextx = x + dir[i][0]; nexty = y + dir[i][1],进行越界访问判断,之后进入递归。

    这里需要注意的一点就是,本题没有用到回溯的部分,是因为要进行递归处理的是visited数组的值,而他的值本身都是0,那么在递归之后并不用回溯再重新赋值

卡玛网测试

三部曲版本

这里用个坑需要注意,刚开始一之找不到,每次岛屿数量都是7。后面才发现他是将每个陆地都进行了计数,那么问题就是就是在dfs部分中的visited。原因在于对于visited参数需要引用传递,就是加上“&”,否则修改了的visited无法进行下一次递归

点击查看代码
#include<iostream>
#include<vector>
using namespace std;
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 (grid[x][y] == 0 || 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;
        // dfs递归
		if (grid[nextx][nexty] == 1 && visited[nextx][nexty] == 0) {
			dfs(grid, visited, nextx, nexty);
		}
        
    }
}

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

第二种版本

这道题主要修改的部分就是一开始发现一个新岛屿的时候,会在主函数中对其进行visited赋值为1,之后在dfs中进行赋值的就是nextx和nexty

点击查看代码
#include<iostream>
#include<vector>
using namespace std;
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) {
    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递归
        if (visited[nextx][nexty] != 1 && grid[nextx][nexty] == 1) {
            visited[nextx][nexty] = 1;
            dfs(grid, visited, nextx, nexty);
        }
    }
}

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

卡玛网99(广搜)

题目描述:卡玛网99
文档讲解:代码随想录(programmercarl)99. 岛屿数量
视频讲解:图论:广搜有陷阱啊!! | 广度优先搜索 | 卡码网:99.岛屿数量

代码随想录视频内容简记

广搜的核心就是利用队列,也不用什么终止条件,也不用什么递归,就是不断把队列中元素上下左右的元素也添加进来,进行访问。

卡玛网测试

这里k哥着重讲了一下关于广搜的坑,就是如果每次push({nextx, nexty})的时候不及时将其的visited置为1,那么就会发生重复添加的情况。就是如果只是加入队列不改变visited的话,那么在if (grid[nextx][nexty] == 1 && visited[nextx][nexty] == 0)判断的时候就会被判断通过,从而导致重复添加

但是还有一点就是可不可以在cur被pop的时候进行当前元素visited的标记呢?我试了一下是可以的,就是visited[cur.first][cur.second] = 1;也能通过,所以关键还是在下面的nextx和nexty的visited要及时置为1

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


void bfs(vector<vector<int>> grid, vector<vector<int>> &visited, int x, int y) {
    queue<pair<int, int>> que;
    que.push({x, y});
    visited[x][y] = 1;
    while (!que.empty()) {
        pair<int, int> cur = que.front();
        que.pop();
        // visited[cur.first][cur.second] = 1;
        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) {
                visited[nextx][nexty] = 1;
                que.push({nextx, nexty});
            }
        }
        
    }
    
}

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

卡玛网100

题目描述:卡码网100
文档讲解:代码随想录(programmercarl)100. 岛屿的最大面积

这个题就比较简单了,就在上面99的基础上稍作修改即可。另外就是有时候会报潜在的数组或指针越界,很多次就是因为写for循环的时候写j的时候写成i了,就比如for (int j = 0; i < M; j++)

卡玛网测试

另外就是可以发现在广搜中不用引用传递也ok,因为广搜中不用递归,只调用一次就可以都搜索得到临近的岛屿。

点击查看代码
#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});
    visited[x][y] = 1;
    int s = 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) {
                s++;
                que.push({nextx, nexty});
                visited[nextx][nexty] = 1;
            }
        }
    }
    sum = max(sum, s);
}


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 i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (grid[i][j] == 1 && visited[i][j] == 0){
                bfs(grid, visited, i, j);
            }
        }
    }
    cout << sum << endl;
}
posted on 2025-03-19 18:31  bnbncch  阅读(21)  评论(0)    收藏  举报