深度优先搜索(DFS)算法模板

server/2025/2/1 8:06:02/

深度优先搜索(DFS,Depth-First Search)是一种用于遍历或搜索树或图的算法。DFS 从起始节点开始,尽可能深入每一条分支,直到无法继续为止。然后回溯到上一个节点,继续未访问的其他分支,直到所有节点都被访问过。

通过一个 岛屿计数 问题来讲解 DFS 的应用。问题要求我们计算一个二维矩阵中所有连通的“岛屿”数量,岛屿由 1 组成,水域由 0 组成。每个岛屿由若干相邻的 1 连接构成,可以上下左右相邻。

问题描述

给定一个 n × m 的二维矩阵,1 表示陆地,0 表示水域。我们需要找到其中所有岛屿的数量。一个岛屿是由相连的 1 组成的区域,相邻的 1 可以通过上下左右方向连接。

深度优先搜索(DFS)算法步骤

  1. 遍历矩阵:从每个未访问的 1 开始,执行 DFS,标记所有与该 1 相连的陆地为已访问,表示找到了一个岛屿。
  2. 回溯标记:DFS 的递归过程会探索当前岛屿所有相连的 1,直到没有更多陆地可访问。
  3. 岛屿计数:每次开始新的 DFS 递归时,岛屿数量加 1。

代码解析

以下是基于 DFS 算法解决岛屿计数问题的 Java 代码模板:

import java.io.*; 
import java.util.*;public class Main {public static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));public static StreamTokenizer in = new StreamTokenizer(br);public static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));public static int[][] dir = { { 0, 1 }, { 1, 0 }, { -1, 0 }, { 0, -1 } };public static void main(String[] args) throws Exception {int n = nextInt();  // 读取行数int m = nextInt();  // 读取列数int[][] arr = new int[n][m];// 读取二维矩阵for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {arr[i][j] = nextInt();}}// 初始化访问标记数组boolean[][] visited = new boolean[n][m];int ans = 0;  // 岛屿计数器// 遍历整个矩阵,执行 DFS 搜索for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {// 如果当前点是陆地并且没有被访问过if (!visited[i][j] && arr[i][j] == 1) {ans++;  // 找到一个岛屿,计数器加1visited[i][j] = true;  // 标记为已访问dfs(visited, i, j, arr);  // 从该点进行 DFS 搜索}}}out.println(ans);  // 输出岛屿数量out.flush();out.close();br.close();}// 深度优先搜索函数,标记所有相连的陆地public static void dfs(boolean[][] visited, int x, int y, int[][] arr) {// 四个方向的移动(右,下,上,左)for (int i = 0; i < 4; i++) {int nextX = x + dir[i][0];int nextY = y + dir[i][1];// 检查新位置是否越界if (nextX < 0 || nextY < 0 || nextX >= arr.length || nextY >= arr[0].length) {continue;  // 越界则跳过}// 如果当前格子是陆地并且未访问过if (!visited[nextX][nextY] && arr[nextX][nextY] == 1) {visited[nextX][nextY] = true;  // 标记为已访问dfs(visited, nextX, nextY, arr);  // 递归继续搜索}}}// 读取整数输入public static int nextInt() throws Exception {in.nextToken();return (int) in.nval;}

关键点解析

  1. 矩阵输入

    • 使用 StreamTokenizer 读取输入,这对于大规模输入数据非常高效。可以将其替换为更常见的 Scanner,根据实际需求选择输入方式。
  2. DFS 函数

    • dfs 函数的作用是从当前节点 (x, y) 开始,递归访问所有与其相连的陆地 1,并将其标记为已访问。我们用 visited 数组来记录哪些节点已经访问过。
    • dir 数组定义了四个方向(右、下、上、左),通过 nextXnextY 来计算相邻的节点坐标。
  3. 岛屿计数

    • 每当我们在 arr[i][j] == 1 且该位置尚未被访问时,我们认为发现了一个新的岛屿,岛屿计数器 ans 加 1。然后通过 DFS 遍历这个岛屿,并标记所有相连的陆地。
  4. 边界检查

    • dfs 函数中,边界检查非常重要,因为我们要确保递归不会访问超出矩阵范围的节点。检查是否越界的代码如下:
if (nextX < 0 || nextY < 0 || nextX >= arr.length || nextY >= arr[0].length)continue;

时间复杂度分析

  • 时间复杂度O(n * m),其中 n 是矩阵的行数,m 是列数。每个节点最多被访问一次,因此总体复杂度是矩阵的大小。
  • 空间复杂度O(n * m),主要用于存储 visited 数组和递归调用栈。

http://www.ppmy.cn/server/164015.html

相关文章

51单片机开发:独立键盘实验

实验目的&#xff1a;按下键盘1时&#xff0c;点亮LED灯1。 键盘原理图如下图所示&#xff0c;可见&#xff0c;由于接GND&#xff0c;当键盘按下时&#xff0c;P3相应的端口为低电平。 键盘按下时会出现抖动&#xff0c;时间通常为5-10ms&#xff0c;代码中通过延时函数delay…

布林线(BOLL)

BOLL上轨的意义 BOLL指标由上轨、中轨和下轨组成&#xff0c;上轨是股价运行的“压力线”&#xff0c;当股价突破上轨时&#xff0c;通常意味着市场处于极度强势的上涨行情。但如果股价在突破上轨后无法持续维持在上轨上方&#xff0c;而是开始回落并跌破上轨&#xff0c;这往往…

Vue 3 项目结构及核心文件

Vue 3 是一个流行的前端框架&#xff0c;它提供了一种高效、灵活的方式来构建用户界面。在这篇博客中&#xff0c;我们将深入探讨一个标准 Vue 3 项目的目录结构&#xff0c;并详细介绍 main.ts 和 App.vue 这两个核心文件。 目录结构 首先&#xff0c;让我们来看一下一个典型…

最近最少使用算法(LRU最近最少使用)缓存替换算法

含义 最近最少使用算法&#xff08;LRU&#xff09;是一种缓存替换算法&#xff0c;用于在缓存空间有限的情况下&#xff0c;选择最少使用的数据项进行替换。该算法的核心思想是基于时间局部性原理&#xff0c;即刚被访问的数据在未来也很有可能被再次访问。 实现 LRU算法的…

华为Ascend产品

文章目录 昇腾 AI服务器 昇腾 AI服务器 昇腾 AI服务器 - ZOMI Atlas 800 训练服务器 - 模型图

【2024年华为OD机试】 (A卷,200分)- 最大化控制资源成本(JavaScriptJava PythonC/C++)

一、问题描述 任务混部问题解析 问题描述 公司创新实验室需要解决一个任务混部问题,目标是最小化资源成本并最大化资源利用率。给定一批任务,每个任务有开始时间、结束时间和并行度三个属性。并行度表示任务运行时占用的服务器数量。任务运行完成后立即释放服务器。要求计…

Unet 改进:在encoder和decoder间加入TransformerBlock

目录 1. TransformerBlock 2. Unet 改进 3. 完整代码 Tips:融入模块后的网络经过测试,可以直接使用,设置好输入和输出的图片维度即可 1. TransformerBlock TransformerBlock是Transformer模型架构的基本组件,广泛应用于机器翻译、文本摘要和情感分析等自然语言处理任务…

2025数学建模美赛|A题成品论文

A题 摘要 本研究提出了一种数学建模方法&#xff0c;旨在帮助考古学家基于台阶磨损模式得出关于台阶使用情况的基本结论。通过模型的建立&#xff0c;我们解决了两个主要任务&#xff1a;首先是从磨损模式中推测台阶的使用频率、行走方向偏好和同时使用人数&#xff1b;其次是在…