跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

深度优先搜索(DFS)与递归算法及经典案例解析

介绍深度优先搜索(DFS)与递归算法的基本概念及应用场景。通过三个典型案例进行讲解:一是基于坐标数位和的寻宝问题,计算最大黄金获取量;二是基于接触矩阵的精准核酸检测圈定,统计需检测人数;三是树结构中的小家庭财富计算,求最大财富和。代码示例采用 Java 实现,展示了 DFS 在图遍历、连通性分析及树形结构处理中的具体用法。

人间失格发布于 2026/3/28更新于 2026/7/2446 浏览
深度优先搜索(DFS)与递归算法及经典案例解析

深度优先搜索(DFS)、递归

  • 深度优先搜索(Depth First Search,DFS)是一种用于遍历或搜索树或图的算法。在 DFS 算法中,从起始节点开始,沿着一条路径尽可能深地访问节点,直到到达叶子节点或者无法继续前进为止。然后退回到最近的一个有未探索节点的分支节点,继续探索其他路径,直到所有节点都被访问过为止。
  • 深度优先搜索常常用于解决以下类型的问题:
    • 图遍历:在无向图或有向图中寻找特定节点之间的路径、判断图的连通性等。
    • 连通性问题:判断图中是否存在环、判断图的强连通分量等。
    • 组合问题:生成排列、组合或子集等组合型问题。
    • 寻路问题:求解从起始点到目标点的最短路径或所有可行路径。
    • 递归问题:通过递归实现深度优先搜索,例如二叉树的遍历等。
小华最多能得到多少克黄金
  • 题目描述:小华按照地图去寻宝,地图上被划分成 m 行和 n 列的方格,横纵坐标范围分别是 [0, n-1] 和 [0, m-1]。在横坐标和纵坐标的数位之和不大于 k 的方格中存在黄金(每个方格中仅存在一克黄金),但横坐标和纵坐标之和大于 k 的方格存在危险不可进入。小华从入口 (0,0) 进入,任何时候只能向左,右,上,下四个方向移动一格。请问小华最多能获得多少克黄金?
  • 输入要求:坐标取值范围如下:k 的取值范围如下:输入中包含 3 个整数,分别是 m, n, k
    • 0 ≤ m ≤ 50
    • 0 ≤ n ≤ 50
    • 0 ≤ k ≤ 100
  • 输出要求:输出小华最多能获得多少克黄金
  • 说明:对于数字 1234,它的各个位上的数字分别是 1、2、3 和 4,那么它的数位之和就等于 1+2+3+4=10。同样地,对于数字 56789,它的数位之和就等于 5+6+7+8+9=35。在题目中,提到横纵坐标的数位之和不大于 k,意味着将横坐标和纵坐标的每个位上的数字相加,得到的和要小于或等于 k。
  • 解题思路:首先,可以定义一个函数 dfs 来进行深度优先搜索。这个函数可以接受当前位置的坐标 (x, y)、当前黄金数量 gold 和已经访问过的方格集合 visited 作为参数。在 dfs 函数中,首先判断当前位置是否越界或者已经访问过,如果是则直接返回。然后判断当前位置的横纵坐标的数位之和是否大于 k,如果是则说明是危险方格,也直接返回。否则,将当前位置标记为已访问,并将当前位置的黄金数量加上当前方格的黄金数量。接下来,递归地调用 dfs 函数来搜索当前位置的上、下、左、右四个方向的相邻方格。对于每个相邻方格,传入更新后的坐标和黄金数量,并将得到的结果取最大值。最后,在主函数中,从入口位置 (0, 0) 开始调用 dfs 函数,并输出返回的最大黄金数量。

题解

import java.util.*;

public class Main {
    static int m, n, k;
    static int[] xArr = {-1, 1, 0, 0}, yArr = {0, 0, 1, -1};

    public static void main(String[] args) {
            (System.in);
         (sc.hasNext()) {
            m = sc.nextInt();
            n = sc.nextInt();
            k = sc.nextInt();
            System.out.println(move(, , ,  <>()));
        }
    }

        {
         (x <  || x > n -  || y <  || y > m -  || visited.contains(x +  + y) || calculate(x) + calculate(y) > k)
             ret;
        ret++;
        visited.add(x +  + y);
         (   ; i < ; i++)
            ret = Math.max(ret, move(x + xArr[i], y + yArr[i], ret, visited));
         ret;
    }

        {
           ;
         (n > ) {
            ret += n % ;
            n /= ;
        }
         ret;
    }
}
Scanner
sc
=
new
Scanner
while
0
0
0
new
HashSet
public
static
int
move
(int x, int y, int ret, Set<String> visited)
if
0
1
0
1
","
return
","
for
int
i
=
0
4
return
public
static
int
calculate
(int n)
int
ret
=
0
while
0
10
10
return

用例 1

输入:40 40 18
输出:1484

用例 2

输入:5 4 7
输出:20
精准核酸检测
  • 题目描述:为了达到新冠疫情精准防控的需要,为了避免全员核酸检测带来的浪费,需要精准圈定可能被感染的人群。现在根据传染病流调以及大数据分析,得到了每个人之间在时间、空间上是否存在轨迹交叉。现在给定一组确诊人员编号(X1, X2, X3,…, Xn),在所有人当中,找出哪些人需要进行核酸检测,输出需要进行核酸检测的人数。(注意:确诊病例自身不需要再做核酸检测)需要进行核酸检测的人,是病毒传播链条上的所有人员,即有可能通过确诊病例所能传播到的所有人。例如:A 是确诊病例,A 和 B 有接触、B 和 C 有接触、C 和 D 有接触、D 和 E 有接触,那么 B、C、D、E 都是需要进行核酸检测的人。
  • 输入要求:第一行为总人数 N;第二行为确认病例人员编号(确诊病例人员数量 < N),用逗号分割;第三行开始,为一个 N * N 的矩阵,表示每个人员之间是否有接触,0 表示没有接触,1 表示有接触。
  • 输出要求:整数:需要做核酸检测的人数
  • 特别说明:人员编号从 0 开始;0 < N < 100

题解

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            int n = Integer.parseInt(sc.nextLine());
            int[] arr = Arrays.stream(sc.nextLine().split(",")).mapToInt(Integer::parseInt).toArray();
            int[][] arrs = new int[n][n];
            for (int i = 0; i < n; i++)
                arrs[i] = Arrays.stream(sc.nextLine().split(",")).mapToInt(Integer::parseInt).toArray();
            HashSet<Integer> set = new HashSet<>(); // 存储确诊和需要检测的人
            for (int i : arr) {
                set.add(i);
                reDo(i, arrs, set);
            }
            System.out.println(set.size() - arr.length); // 减去确诊人数
        }
    }

    public static void reDo(int i, int[][] arrs, HashSet<Integer> set) {
        for (int j = 0; j < arrs[i].length; j++) {
            if (arrs[i][j] == 1 && !set.contains(j)) {
                // 递归终止条件
                set.add(j);
                reDo(j, arrs, set);
            }
        }
    }
}

用例 1

输入:5
1,2
1,1,0,1,0
1,1,0,0,0
0,0,1,0,1
1,0,0,1,0
0,0,1,0,1
输出:3
说明:编号为 1、2 号的人员,为确诊病例。1 号与 0 号有接触,0 号与 3 号有接触;2 号与 4 号有接触;故 0、3、4 号共 3 人需要核酸检测
最富裕的小家庭
  • 题目描述:在一颗树中,每个节点代表一个家庭成员,节点的数字表示其个人的财富值,一个节点及其直接相连的子节点被定义为一个小家庭。现给你一颗树,请计算出最富裕的小家庭的财富和。
  • 输入要求:第一行为一个数 N,表示成员总数,成员编号 1N。1 ≤ N ≤ 1000;第二行为 N 个空格分隔的数,表示编号 1N 的成员的财富值。0 ≤ 财富值 ≤ 1000000;接下来 N -1 行,每行两个空格分隔的整数(N1, N2),表示 N1 是 N2 的父节点。
  • 输出要求:最富裕的小家庭的财富和

题解

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            int n = sc.nextInt();
            int[] arr = new int[n + 1]; // 数组索引从 0 开始,成员编号从 1 开始,故 n 个成员需要 n+1 大小数组
            for (int i = 0; i < n; i++) // 成员编号从 1 开始,以成员编号作为数组索引
                arr[i + 1] = sc.nextInt();
            List<List<Integer>> list = new ArrayList<>();
            for (int i = 0; i <= n; i++) // 集合 add 从索引 0 开始,从索引 1 开始与成员编号对齐
                list.add(new ArrayList<>());
            for (int i = 0; i < n - 1; i++)
                list.get(sc.nextInt()).add(sc.nextInt());
            int max = 0;
            for (int i = 1; i <= n; i++) {
                int sum = arr[i];
                for (Integer sun : list.get(i)) // 遍历该成员编号的所有直接连接的子节点
                    sum += arr[sun];
                max = Math.max(max, sum);
            }
            System.out.println(max);
        }
    }
}

用例 1

输入:4
100 200 300 500
1 2
1 3
2 4
输出:700
说明:成员 1,2,3 组成的小家庭财富值为 600,成员 2,4 组成的小家庭财富值为 700

用例 2

输入:4
100 200 300 500
1 2
1 3
1 4
输出:1100
说明:成员 1,2,3 组成的小家庭财富值为 600,成员 2,4 组成的小家庭财富值为 700

目录

  1. 深度优先搜索(DFS)、递归
  2. 小华最多能得到多少克黄金
  3. 精准核酸检测
  4. 最富裕的小家庭
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 吴恩达团队研究:多模态多样本上下文学习无需微调即可适应新任务
  • OpenClaw + Kimi K2.5 本地私有化部署与办公自动化实战
  • C++ GESP 三级认证手册:计算机基础与算法
  • 数据结构:带头双向循环链表详解与实现
  • FastGPT 结合 MCP 协议构建工具增强型智能体
  • AgentScope Java 实战:构建 AI 奶茶店应用
  • Python 常用库实用清单:从数值计算到深度学习
  • WebAssembly 技术全景解析:重塑 Web 与原生边界
  • TinyLlama 与 LiteLlama:轻量级模型实现高性能推理与应用
  • 基于 ASP.NET Core 和 Python 的 PDF 转 Word 工具开发与部署实践
  • Python 办公自动化:使用 Pandas 库操作 Excel
  • Python 一键拆分 PDF:按章节建文件夹并导出单页(支持书签与正文识别)
  • Linux 核心 IO 模型深析:非阻塞 IO 与多路转接实现
  • Element UI Table 设置 max-height 后右侧滚动条空白占位处理
  • Python 开发环境搭建与基础入门指南
  • Pencil.dev:AI 驱动设计画布与代码生成工具实战指南
  • Cursor Chat Browser:管理 AI 聊天历史的 Web 应用
  • Python 爬虫实战:爬取今日头条图文标题
  • Android Studio 集成 GitHub Copilot GPT-4o:AI 辅助开发实战与避坑指南
  • 基于 Codex GitHub Action 的自动化代码审查实践

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online