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

别再死记模板!用两种方法(DFS和树形DP)搞定树的直径,C++代码逐行解析

深入解析树的直径从DFS到树形DP的C实战指南树结构在算法竞赛和实际工程中无处不在而树的直径作为衡量树规模的重要指标其求解方法一直是面试和竞赛中的高频考点。很多学习者虽然能背诵模板代码却对背后的原理一知半解。本文将彻底拆解两种主流解法——两次DFS法和树形DP法通过可视化分析、复杂度对比和典型用例带你真正掌握这一核心算法。1. 树的直径基础与两次DFS法树的直径定义为树中任意两节点间最长路径的长度。想象一下如果这棵树是城市间的道路网直径就是相隔最远的两个城市之间的距离。这个看似简单的概念在实际应用中却有着丰富的变体和求解技巧。1.1 两次DFS法的核心原理两次DFS法基于一个关键定理从任意节点出发进行DFS到达的最远节点必然是直径的一个端点。这个结论的直观理解是直径作为树中最长的路径其端点必然是彼此最远的两个节点。void dfs(int u, int fa, int depth, int maxDepth, int farthestNode) { if (depth maxDepth) { maxDepth depth; farthestNode u; } for (int v : adj[u]) { if (v ! fa) { dfs(v, u, depth 1, maxDepth, farthestNode); } } }表DFS关键参数说明参数类型作用uint当前访问节点faint父节点避免回访depthint当前累计深度maxDepthint记录最大深度引用传递farthestNodeint记录最远节点引用传递1.2 算法实现与复杂度分析完整的两步DFS实现如下pairint, int findDiameterDFS(vectorvectorint tree) { int n tree.size(); int end1 0, maxDepth 0; // 第一次DFS从任意节点这里选0找到最远节点end1 functionvoid(int, int, int) dfs [](int u, int fa, int depth) { if (depth maxDepth) { maxDepth depth; end1 u; } for (int v : tree[u]) { if (v ! fa) dfs(v, u, depth 1); } }; dfs(0, -1, 0); // 第二次DFS从end1出发找到最远节点end2 int end2 end1, diameter 0; maxDepth 0; dfs(end1, -1, 0); diameter maxDepth; end2 end1; // 注意这里end1已被更新为最远节点 return {diameter, end2}; }时间复杂度O(n)每个节点被访问两次空间复杂度O(n)递归栈空间和邻接表存储注意该方法仅适用于边权均为正的情况。若存在负权边最远节点可能不在直径端点上。2. 树形DP处理负权边的通用解法当树中存在负权边时两次DFS法失效。这时需要更强大的工具——树形动态规划。这种方法不仅适用于所有边权情况还能在求解过程中获得更多子树信息。2.1 树形DP的核心思想定义两个状态数组d1[u]以u为根的子树中u到叶子节点的最长路径d2[u]以u为根的子树中u到叶子节点的次长路径与最长路径无公共边树的直径就是所有节点中d1[u] d2[u]的最大值。这种方法的精妙之处在于它通过后序遍历自底向上地计算每个子树的贡献。int diameter 0; void dfsDP(int u, int fa) { d1[u] d2[u] 0; for (auto [v, w] : adj[u]) { if (v fa) continue; dfsDP(v, u); int t d1[v] w; if (t d1[u]) { d2[u] d1[u]; d1[u] t; } else if (t d2[u]) { d2[u] t; } } diameter max(diameter, d1[u] d2[u]); }2.2 带权树的实现变体对于带权树我们需要在状态转移时考虑边权。以下是支持负权边的完整实现struct Edge { int to, weight; }; vectorvectorEdge adj; vectorint d1, d2; int diameter; void computeDiameter() { int n adj.size(); d1.assign(n, 0); d2.assign(n, 0); diameter 0; functionvoid(int, int) dfs [](int u, int fa) { for (auto [v, w] : adj[u]) { if (v fa) continue; dfs(v, u); int t d1[v] w; if (t d1[u]) { d2[u] d1[u]; d1[u] t; } else if (t d2[u]) { d2[u] t; } } diameter max(diameter, d1[u] d2[u]); }; dfs(0, -1); }表树形DP状态转移分析情况处理方式示例场景新路径 d1d2继承d1d1更新发现更长分支d1 新路径 d2仅更新d2发现新的次长分支新路径 d2忽略非关键路径3. 两种方法的深度对比与选择策略3.1 性能与适用场景对比表DFS与DP方法对比特性两次DFS法树形DP法时间复杂度O(n)O(n)空间复杂度O(n)O(n)负权边支持不支持支持实现难度较简单中等额外信息仅直径长度各子树深度信息适用场景无权树或正权树所有类型树3.2 典型应用场景分析网络延迟分析在计算机网络中树的直径可以反映最坏情况下的通信延迟。如果边权表示延迟时间必须使用树形DP法。社交网络影响传播在社交网络树形结构中直径两端的人物通常是信息传播的关键节点。此时使用两次DFS法更高效。资源分配优化如医院选址问题需要同时考虑树的重心和直径特性这时树形DP法能提供更多子树信息。// 医院选址问题中的综合应用示例 void findOptimalLocation(vectorvectorEdge tree, vectorint population) { vectorint totalDist(tree.size(), 0); vectorint subtreeSize(tree.size(), 0); int minTotalDist INT_MAX; int bestLocation 0; functionvoid(int, int) dfs [](int u, int fa) { subtreeSize[u] population[u]; for (auto [v, w] : tree[u]) { if (v fa) continue; dfs(v, u); subtreeSize[u] subtreeSize[v]; totalDist[u] totalDist[v] subtreeSize[v] * w; } }; functionvoid(int, int, int) reroot [](int u, int fa, int n) { if (totalDist[u] minTotalDist) { minTotalDist totalDist[u]; bestLocation u; } for (auto [v, w] : tree[u]) { if (v fa) continue; totalDist[v] totalDist[u] (n - 2 * subtreeSize[v]) * w; reroot(v, u, n); } }; dfs(0, -1); reroot(0, -1, subtreeSize[0]); cout 最佳位置: bestLocation 最小总距离: minTotalDist endl; }4. 实战演练与常见陷阱4.1 典型测试用例设计基础验证用例3 1 2 2 3预期直径2路径1-2-3多分支复杂树7 1 2 1 3 1 4 2 5 2 6 3 7预期直径4如路径5-2-1-3-7含负权边树4 1 2 5 1 3 -2 3 4 8预期直径11路径2-1-3-44.2 常见错误与调试技巧递归栈溢出对于深度较大的树递归实现可能导致栈溢出。可以改用迭代DFS或设置编译器栈大小。父节点检查遗漏忘记跳过父节点会导致无限循环。确保每次递归都传递父节点信息。负权边处理不当在两次DFS法中未检查边权正负导致错误结果。使用前务必确认问题约束。初始状态设置错误在树形DP中忘记初始化d1和d2数组会导致计算错误。// 迭代DFS实现示例避免递归栈溢出 void iterativeDFS(int start, vectorint distances, const vectorvectorint tree) { stackpairint, int s; // {node, parent} s.push({start, -1}); distances[start] 0; while (!s.empty()) { auto [u, fa] s.top(); s.pop(); for (int v : tree[u]) { if (v ! fa distances[v] -1) { distances[v] distances[u] 1; s.push({v, u}); } } } }在实际编码面试中建议先明确说明方法选择理由如因为题目保证边权为正我选择实现更简单的两次DFS法然后逐步实现并验证边界条件。

相关文章:

别再死记模板!用两种方法(DFS和树形DP)搞定树的直径,C++代码逐行解析

深入解析树的直径:从DFS到树形DP的C实战指南 树结构在算法竞赛和实际工程中无处不在,而树的直径作为衡量树规模的重要指标,其求解方法一直是面试和竞赛中的高频考点。很多学习者虽然能背诵模板代码,却对背后的原理一知半解。本文将…...

Q-Tuning:高效NLP模型微调的双粒度剪枝策略

1. 项目概述在自然语言处理领域,监督微调(Supervised Fine-Tuning)是提升预训练模型性能的关键步骤。然而,随着模型规模的不断扩大,传统微调方法面临着显存占用高、计算开销大等挑战。Q-Tuning作为一种创新的高效微调方…...

【光学】基于matlab菲涅尔光谱和角光谱ASPSAP模拟聚焦高斯光束传播【含Matlab源码 15406期】

💥💥💥💥💥💥💞💞💞💞💞💞💞💞欢迎来到海神之光博客之家💞💞💞&#x1f49…...

思维导图拆解项目范围 3 个真实落地案例

涵盖办公自动化项目、软件研发项目、行政制度落地项目,可直接复制到 XMind / 飞书思维导图 / 幕布 使用,拿来就能套用。通用拆解固定结构(所有案例统一模板)中心主题:项目名称四大主干固定不变:项目交付范围…...

hexo 上传到github命令报错

hexo 上传到github命令报错 D:\Hexo\MyBolg>hexo d INFO Validating config INFO Deploying: git INFO Clearing .deploy_git folder... INFO Copying files from public folder... INFO Copying files from extend dirs... On branch master nothing to commit, worki…...

终极免费文档下载指南:如何一键下载30+文库平台的文档

终极免费文档下载指南:如何一键下载30文库平台的文档 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档,但是相关网站浏览体验不好各种广告,各种登录验证,需要很多步骤才能下载文档,该脚本就是为了解…...

李辉《曾国藩日记》笔记:天气太热,该上奏的事情都放着没起草

李辉《曾国藩日记》笔记:天气太热,该上奏的事情都放着没起草原文:同治元年六月十六日早饭后清理文件,见客一次。围棋一局。写沈幼丹信一、彭雪琴信一,阅《文献通考.中书省》篇。传见高列三、查宝信、廖宇庆三人。 午刻…...

Docker 27 + Ray + Triton联合调度配置终极方案:单节点并发吞吐突破128 req/s的关键11行配置

更多请点击: https://intelliparadigm.com 第一章:Docker 27 AI 容器智能调度配置 Docker 27 引入了原生 AI 驱动的容器调度引擎(AI-Scheduler),通过实时资源画像与模型推理负载特征自动优化 Pod 分配策略。该能力内置…...

你的视频文件太大?这款免费压缩神器5分钟搞定所有格式

你的视频文件太大?这款免费压缩神器5分钟搞定所有格式 【免费下载链接】compressO Convert any video/image into a tiny size. 100% free & open-source. Available for Mac, Windows & Linux. 项目地址: https://gitcode.com/gh_mirrors/co/compressO …...

如何快速提升Mac音频体验:免费系统级音频均衡器的终极指南

如何快速提升Mac音频体验:免费系统级音频均衡器的终极指南 【免费下载链接】eqMac macOS System-wide Audio Equalizer & Volume Mixer 🎧 项目地址: https://gitcode.com/gh_mirrors/eq/eqMac 你是否曾因MacBook音质平淡而烦恼?无…...

效率倍增:结合快马AI与OpenClow,自动化生成合规审批流应用代码

最近在优化公司内部审批系统时,发现传统开发模式下,光是搭建一个费用报销审批应用就要耗费大量时间在重复性编码上。于是尝试结合OpenClow框架和InsCode(快马)平台的AI能力,意外实现了效率的指数级提升。这里记录下具体实践过程,或…...

Win11开发环境救星:手把手教你用Fluent Terminal和WSL2搭建无缝Linux命令行

Win11开发环境终极优化:Fluent Terminal与WSL2深度整合指南 如果你是一名长期在Windows环境下工作的开发者,可能已经对原生CMD和PowerShell的局限性感到厌倦。但切换到Mac或Linux系统又面临成本或兼容性问题。本文将带你彻底改造Win11的命令行体验&#…...

CRMy:为AI销售代理构建记忆中枢,实现上下文驱动的智能销售

1. 项目概述:为AI销售代理构建一个“记忆中枢”如果你正在构建或使用AI销售代理,无论是基于Claude、GPT还是其他大模型,你肯定遇到过这个核心痛点:每次让AI去执行一个动作——比如发一封跟进邮件、推进一个商机阶段、或者预约一次…...

n8n-claw自定义节点:低代码自动化平台的数据抓取与集成方案

1. 项目概述:一个为n8n而生的“数据抓手”如果你正在用n8n构建自动化工作流,大概率遇到过这样的痛点:你需要从某个网站、API或者内部系统里抓取数据,但对方要么没有提供现成的接口,要么接口格式极其别扭,要…...

TVA系统在3C电子行业的技术落地

重磅预告:本专栏将独家连载新书《AI视觉技术:从入门到进阶》精华内容。本书是《AI视觉技术:从进阶到专家》的权威前导篇,特邀美国 TypeOne 公司首席科学家、斯坦福大学博士 Bohan 担任技术顾问。Bohan先生师从美国三院院士、“AI教…...

网盘直链下载助手终极指南:解锁免会员高速下载新体验

网盘直链下载助手终极指南:解锁免会员高速下载新体验 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云…...

ARM多核处理器架构与缓存一致性技术解析

1. ARM多核处理器架构概览现代ARM Cortex-A系列处理器早已从单核时代迈入了多核架构的黄金时期。2004年ARM11 MPCore的推出标志着ARM正式进军多核SoC市场,如今从智能手机到服务器,多核设计已成为性能提升的标配方案。但多核并非简单地将多个CPU核心拼凑在…...

别再死记硬背了!用Multisim仿真带你玩转5个经典运放电路(附仿真文件)

用Multisim仿真5个经典运放电路:从理论到实践的无缝衔接 在电子工程的学习过程中,运算放大器(运放)电路一直是让许多初学者又爱又恨的内容。传统的学习方法往往要求我们死记硬背各种电路公式,在纸上进行繁琐的计算推导…...

Windows系统管理效率革命:从手动配置到模块化自动化的技术演进

Windows系统管理效率革命:从手动配置到模块化自动化的技术演进 【免费下载链接】winutil Chris Titus Techs Windows Utility - Install Programs, Tweaks, Fixes, and Updates 项目地址: https://gitcode.com/GitHub_Trending/wi/winutil 在Windows系统管理…...

ArmSoM CM1:15美元工业级嵌入式模块解析与应用

1. ArmSoM CM1模块解析:15美元的工业级嵌入式解决方案在工业自动化和HMI(人机界面)领域,寻找高性价比、稳定可靠的嵌入式核心模块一直是开发者的痛点。ArmSoM CM1的出现打破了这一局面——这款基于Rockchip RK3506J SoC的系统模块…...

百秋尚美冲刺港交所:年营收近16亿 派息4亿,红杉获8000万股息

雷递网 雷建平 5月4日上海百秋尚美科技服务集团股份有限公司(简称:“百秋尚美”)日前递交招股书,准备在港交所上市。截至2026年3月31日止三个月,百秋尚美来自电商运营服务的GMV达至109.64亿元,进而带动同期…...

C/C++ 图形化界面编程入门:EasyX 完全指南

引言 在C/C编程学习中,我们通常接触的是控制台程序——黑底白字的命令行界面。虽然控制台程序功能强大,但界面单调、用户体验较差。那么,能否用C/C编写带有图形界面的程序呢? 答案是肯定的!我们可以使用图形库来实现…...

LLM角色扮演开发:从数据生成到评估实战

1. 项目背景与核心价值在大语言模型(LLM)应用开发中,角色扮演类交互正成为最热门的落地场景之一。无论是虚拟客服、游戏NPC还是教育助手,让AI具备鲜明的人物特质直接影响用户体验。但开发者面临两个关键痛点:一是高质量…...

STM32硬件SPI驱动AD7124-4:从时序图到代码实现的保姆级避坑指南

STM32硬件SPI驱动AD7124-4:从时序图到代码实现的保姆级避坑指南 在嵌入式高精度数据采集系统中,AD7124-4作为一款24位Σ-Δ型ADC,凭借其优异的噪声性能和灵活的配置选项,成为工业测量领域的明星器件。然而在实际开发中&#xff0c…...

# 018、CrewAI 多智能体协作:角色分配、任务委派与结果聚合

上周五凌晨两点,我盯着终端里一行诡异的报错发呆——CrewAI 跑出来的结果里,两个 Agent 居然互相覆盖了对方的输出字段。一个负责写技术文档的 Researcher,把另一个负责代码审查的 Reviewer 的结论给吞了。这不是 bug,是我没搞清楚…...

数据中台是什么?一文读懂定义、架构与核心能力(2026版)

引言在数字化转型进入深水区的今天,越来越多的企业正在经历同一种困境:数据量越来越大,但能用的数据却越来越少。业务部门拿到的报表互相打架,数据团队疲于应付需求,管理层想做数据驱动决策,却发现找不到一…...

基于知识图谱与RAG的个人知识管理系统:从信息碎片到智能连接

1. 从信息碎片到知识网络:为什么我们需要一个“第二大脑”在信息爆炸的时代,我们每天都在与海量的数字内容打交道:浏览器里几十个待读标签页、下载文件夹里堆积的PDF报告、笔记软件中零散的灵感片段、以及各种社交媒体上收藏的“干货”。我们…...

ai辅助开发新思路:设计智能prompt让快马成为你的mysql配置专家

最近在折腾MySQL的安装配置,发现一个特别有意思的现象:同样的配置需求,不同人搜索到的教程可能千差万别。有的教程推荐5.7版本,有的建议直接上8.0;有的说innodb_buffer_pool_size设成4G就够了,有的却说至少…...

UltraImage:基于Transformer的超高分辨率图像生成技术

1. 项目背景与核心价值分辨率外推(Resolution Extrapolation)一直是计算机视觉领域的硬骨头。传统方案要么依赖暴力插值导致细节模糊,要么通过复杂网络结构带来难以承受的计算开销。UltraImage的出现,标志着基于Transformer架构的…...

收藏必备!小白程序员快速入门:AI Memory如何让大模型成为你的长期协作伙伴?

过去几年,大模型有明显的进步, 它能写文章、写代码、做总结、翻译、分析财报、解释论文,甚至能像一个专业助理一样完成复杂任务。 但很长一段时间里,大模型有一个根本缺陷:它没有真正的记忆。 你今天告诉它的偏好&…...