代码随想录算法训练营第44天|99. 岛屿数量(深搜)、99. 岛屿数量(广搜)、100. 岛屿的最大面积
卡玛网99(深搜)
2025-03-19 18:30:52 星期三
题目描述:卡玛网99
文档讲解:代码随想录(programmercarl)99. 岛屿数量
视频讲解:图论:来用深搜解决一道题目,两种深搜写法,你掉坑了吗? | 卡码网:99.岛屿数量
代码随想录视频内容简记
首先是这道题用深搜的部分在哪里?就算在一片岛屿的时候,需要对这块岛屿进行一个搜索,就在这里。这里用深搜或者广搜都是可以的
梳理
-
将图进行存储
-
主函数进行图的遍历,以及深搜调用和输出打印
-
深搜部分
大致代码内容
-
这里用for循环遍历进行朴素存储,用grid = 1进行表示
-
新建一个visited数组,对图一行一行遍历,一旦有grid标记为1且visited不为1的元素,那么就进入深搜。同时定义一个全局变量dir数组表示四个方向
-
深搜主体采用深搜三部曲
-
确定递归函数及参数。
void dfs (grid, visited, x, y),这里的x和y表示对当前结点的横纵坐标 -
确定递归的终止条件。
if (grid[x][y] == 0 || visited[x][y] == 1) return;,之后要接一句就是visited[x][y] = 1,将当前结点标记为访问过 -
处理目前结点出发的路径。首先用
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;
}
浙公网安备 33010602011771号