当前位置: 首页 > news >正文

Day51--图论--99. 岛屿数量(卡码网),100. 岛屿的最大面积(卡码网)

Day51–图论–99. 岛屿数量(卡码网),100. 岛屿的最大面积(卡码网)

本篇重点,在于理解深搜和广搜遍历顺序的不同,以及深搜广搜对应的坑点。

给出了打印遍历顺序的代码,可以打印出来遍历点直观感受一下。

可以看到,DFS就是不撞南墙不回头;BFS就是像水波纹一样一层一层荡漾开来。

99. 岛屿数量(卡码网)

方法:深搜

思路:

本题思路,是遇到一个没有遍历过的陆地,计数器就加一,然后把该节点所能遍历到的陆地都标记上。

在遇到标记过的陆地节点或海洋节点的时候直接跳过。 这样计数器就是最终岛屿的数量。

import java.util.*;public class Main {// 四个方向:右、下、左,上private static final int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};private static void dfs(int[][] grid, boolean[][] 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.length || nextY < 0 || nextY >= grid[0].length) {continue;}// 如果未访问且是陆地(1),则继续DFSif (!visited[nextX][nextY] && grid[nextX][nextY] == 1) {visited[nextX][nextY] = true;dfs(grid, visited, nextX, nextY);}}}public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();int[][] grid = new int[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {grid[i][j] = in.nextInt();}}// 访问标记数组boolean[][] visited = new boolean[n][m];// 计数器int count = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {// 发现未访问的陆地,岛屿数量加1,并开始DFS标记所有相连的陆地if (!visited[i][j] && grid[i][j] == 1) {visited[i][j] = true;count++;dfs(grid, visited, i, j);}}}System.out.println(count);in.close();}
}

遍历顺序:

DFS访问顺序:1  2  0  0  0 4  3  0  0  0 0  0  5  0  0 0  0  0  6  7 

方法:广搜

思路:

只要加入队列就代表走过,就需要标记,而不是从队列拿出来的时候再去标记走过。

import java.util.*;public class Main {// 四个方向:右、下、左,上private static final int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};// 广搜private static void bfs(int[][] grid, boolean[][] visited, int x, int y) {Deque<int[]> que = new ArrayDeque<>();// 存储节点坐标que.offer(new int[] {x, y});// 加入队列后立即标记为已访问visited[x][y] = true;while (!que.isEmpty()) {int[] cur = que.poll();int curX = cur[0];int curY = cur[1];// 四个方向都遍历一遍for (int i = 0; i < 4; i++) {int nextX = curX + dir[i][0];int nextY = curY + dir[i][1];// 检查是否越界if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {continue;}// // 如果是未访问的陆地,则加入队列并标记if (!visited[nextX][nextY] && grid[nextX][nextY] == 1) {que.offer(new int[] {nextX, nextY});visited[nextX][nextY] = true;}}}}public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();int[][] grid = new int[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {grid[i][j] = in.nextInt();}}// 访问标记数组boolean[][] visited = new boolean[n][m];// 计数器int count = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {// 发现未访问的陆地,岛屿数量加1,并开始BFS标记所有相连的陆地if (!visited[i][j] && grid[i][j] == 1) {count++;bfs(grid, visited, i, j);}}}System.out.println(count);in.close();}
}

遍历顺序:

DFS访问顺序:1  2  0  0  0 4  3  0  0  0 0  0  5  0  0 0  0  0  6  7 
BFS访问顺序:1  2  0  0  0 3  4  0  0  0 0  0  5  0  0 0  0  0  6  7 

遍历顺序打印

思路:

可以复制代码,修改代码中的矩阵,打印出来,直观看看每一步都是怎么走的。

import java.util.LinkedList;
import java.util.Queue;public class TraversalOrder {// 四个方向:右、下、左,上private static final int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};private static int count;// DFS遍历并记录访问顺序private static void dfs(int[][] grid, int[][] order, 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.length && nexty >= 0 && nexty < grid[0].length) {if (grid[nextx][nexty] == 1 && order[nextx][nexty] == 0) {count++;order[nextx][nexty] = count;dfs(grid, order, nextx, nexty);}}}}// BFS遍历并记录访问顺序private static void bfs(int[][] grid, int[][] order, int x, int y) {Queue<int[]> queue = new LinkedList<>();queue.offer(new int[]{x, y});count++;order[x][y] = count;while (!queue.isEmpty()) {int[] cur = queue.poll();int curx = cur[0];int cury = cur[1];for (int i = 0; i < 4; i++) {int nextx = curx + dir[i][0];int nexty = cury + dir[i][1];if (nextx >= 0 && nextx < grid.length && nexty >= 0 && nexty < grid[0].length) {if (grid[nextx][nexty] == 1 && order[nextx][nexty] == 0) {count++;order[nextx][nexty] = count;queue.offer(new int[]{nextx, nexty});}}}}}// 打印访问顺序矩阵private static void printOrder(int[][] order) {for (int i = 0; i < order.length; i++) {for (int j = 0; j < order[0].length; j++) {System.out.printf("%2d ", order[i][j]);}System.out.println();}}public static void main(String[] args) {// 初始化给定的矩阵int[][] grid = {{1, 1, 1, 1, 1},{1, 1, 1, 1, 1},{1, 1, 1, 1, 1},{1, 1, 1, 1, 1},{1, 1, 1, 1, 1}};int n = grid.length;int m = grid[0].length;// 演示DFS访问顺序System.out.println("DFS访问顺序:");int[][] dfsOrder = new int[n][m];count = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (grid[i][j] == 1 && dfsOrder[i][j] == 0) {count++;dfsOrder[i][j] = count;dfs(grid, dfsOrder, i, j);}}}printOrder(dfsOrder);// 演示BFS访问顺序System.out.println("\nBFS访问顺序:");int[][] bfsOrder = new int[n][m];count = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (grid[i][j] == 1 && bfsOrder[i][j] == 0) {bfs(grid, bfsOrder, i, j);}}}printOrder(bfsOrder);}
}

目前代码打印效果

DFS访问顺序:
1  2  3  4  5 
22 23 24 25  6 
21 20 19 18  7 
14 15 16 17  8 
13 12 11 10  9 
BFS访问顺序:
1  2  4  7 11 
3  5  8 12 16 
6  9 13 17 20 
10 14 18 21 23 
15 19 22 24 25 

可以看到,DFS就是不撞南墙不回头;BFS就是像水波纹一样一层一层荡漾开来。

100. 岛屿的最大面积(卡码网)

方法:深搜

思路:

在dfs递归的时候统计,每一层递归向上返回本次遍历到的岛屿数。

主函数里的循环,每次都是遇到一个新的岛屿,所以在主函数里,dfs回来之后,刷新maxLand。

import java.util.*;public class Main {// 四个方向:右、下、左,上private static final int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};private static int dfs(int[][] grid, boolean[][] visited, int x, int y) {// 坐标为x,y的本节点int sum = 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.length || nextY < 0 || nextY >= grid[0].length) {continue;}// 如果未访问且是陆地(1),则继续DFSif (!visited[nextX][nextY] && grid[nextX][nextY] == 1) {visited[nextX][nextY] = true;// 加上从这个节点出发,深搜到的所有节点sum += dfs(grid, visited, nextX, nextY);}}// 返回给上一层return sum;}public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();int[][] grid = new int[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {grid[i][j] = in.nextInt();}}// 访问标记数组boolean[][] visited = new boolean[n][m];int maxLand = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {// 发现未访问的陆地,岛屿数量加1,并开始DFS标记所有相连的陆地if (!visited[i][j] && grid[i][j] == 1) {visited[i][j] = true;// 每次从这里进去的,是一整个岛屿int land = dfs(grid, visited, i, j);// 刷新最大岛屿面积maxLand = Math.max(maxLand, land);}}}System.out.println(maxLand);in.close();}
}

方法:深搜

思路:

全局变量maxLand和count。

主函数里的循环,每次都是遇到一个新的岛屿,所以在主函数里,dfs之前,重置count=0,dfs回来之后,刷新maxLand。

import java.util.*;public class Main {// 四个方向:右、下、左,上private static final int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};private static int maxLand = 0;private static int count = 0;private static void dfs(int[][] grid, boolean[][] visited, int x, int y) {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.length || nextY < 0 || nextY >= grid[0].length) {continue;}// 如果未访问且是陆地(1),则继续DFSif (!visited[nextX][nextY] && grid[nextX][nextY] == 1) {visited[nextX][nextY] = true;dfs(grid, visited, nextX, nextY);}}}public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();int[][] grid = new int[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {grid[i][j] = in.nextInt();}}// 访问标记数组boolean[][] visited = new boolean[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {// 发现未访问的陆地,岛屿数量加1,并开始DFS标记所有相连的陆地if (!visited[i][j] && grid[i][j] == 1) {visited[i][j] = true;count = 0;dfs(grid, visited, i, j);maxLand = Math.max(res, count);}}}System.out.println(maxLand);in.close();}
}

方法:广搜

思路:

同上,接着用全局变量的方法,使用maxLand和count计数。

当队列que出队的时候,count++;

当回到主函数的时候,刷新maxLand。

import java.util.*;public class Main {// 四个方向:右、下、左,上private static final int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};private static int maxLand = 0;private static int count = 0;// 广搜private static void bfs(int[][] grid, boolean[][] visited, int x, int y) {Deque<int[]> que = new ArrayDeque<>();// 存储节点坐标que.offer(new int[] {x, y});// 加入队列后立即标记为已访问visited[x][y] = true;while (!que.isEmpty()) {// 每次弹出队列的时候,节点+1,岛屿面积++count++;int[] cur = que.poll();int curX = cur[0];int curY = cur[1];// 四个方向都遍历一遍for (int i = 0; i < 4; i++) {int nextX = curX + dir[i][0];int nextY = curY + dir[i][1];// 检查是否越界if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {continue;}// // 如果是未访问的陆地,则加入队列并标记if (!visited[nextX][nextY] && grid[nextX][nextY] == 1) {que.offer(new int[] {nextX, nextY});visited[nextX][nextY] = true;}}}}public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();int[][] grid = new int[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {grid[i][j] = in.nextInt();}}// 访问标记数组boolean[][] visited = new boolean[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {// 发现未访问的陆地,岛屿数量加1,并开始BFS标记所有相连的陆地if (!visited[i][j] && grid[i][j] == 1) {count = 0;bfs(grid, visited, i, j);maxLand = Math.max(maxLand, count);}}}System.out.println(maxLand);in.close();}
}
http://www.lryc.cn/news/619726.html

相关文章:

  • 【数据结构】——栈(Stack)的原理与实现
  • 最新Coze(扣子)智能体工作流:用Coze实现「图片生成-视频制作」全自动化,3分钟批量产出爆款内容
  • 自由学习记录(83)
  • 【Unity开发】Unity核心学习(一)
  • 简单了解:CS5803芯片技术解析:HDMI到V-by-One的信号转换
  • BGP特性笔记
  • Cursor替代品:亚马逊出品,Kiro免费使用Claude Sonnet4.0一款更注重流程感的 AI IDE
  • PG靶机 - PayDay
  • lowbit函数
  • 打靶日常-文件上传
  • 《Power Voronoi图的数学原理》
  • latex 中将新的一个section重新从1开始排序,而不是和前面的section继续排序
  • PHP Word 批注处理工程设计方案(基于 `docx` 模板 + 批注驱动)
  • 【Word VBA Zotero 引用宏错误分析与改正指南】【解决[21–23]参考文献格式插入超链接问题】
  • [AI React Web] E2B沙箱 | WebGPU | 组件树 | 智能重构 | 架构异味检测
  • Navicat 询问 AI | 优化 SQL 查询
  • 打造专属 React 脚手架:从 0 到 1 开发 CLI 工具
  • Redis中灵活结合SET和SETEX的方法及多语言工具库实现
  • C#自定义日期时间选择器
  • 用python可视化分析海南自贸港封关运作:动因、影响
  • velero 资源备份测试
  • 达梦数据库常见漏洞及处理方案
  • 计算机网络---用户数据报协议User Datagram Protocol(UDP)
  • Unity新手制作跑酷小游戏详细教程攻略
  • CMake笔记:配置(Configure)、生成(Generate)和构建(Build)
  • B站 韩顺平 笔记 (Day 17)
  • c++编程题-笔记
  • 电商双11美妆数据分析
  • 《Foundations and Recent Trends in Multimodal Mobile Agents: A Survey》论文精读笔记
  • 2025年手游防护终极指南:四维防御体系破解DDoS、外挂与协议篡改