## 1. 问题背景与核心挑战 最近在刷算法题时遇到一道很有意思的树形DP问题——Tree Distances II。题目给定一棵包含n个节点的树要求计算每个节点到其他所有节点的距离之和。初看觉得直接暴力DFS就能解决但仔细一想当n达到1e5量级时O(n²)的复杂度显然会TLE。这让我开始思考如何用O(n)或O(nlogn)的复杂度优雅解决这个问题。 这类树形动态规划问题在实际开发中其实很常见。比如在社交网络分析中我们可能需要计算某个用户到其他所有用户的关系距离在分布式系统中需要优化节点间的通信成本甚至在前端渲染大型DOM树时也需要类似思路来优化遍历性能。理解这类算法对提升实际问题解决能力很有帮助。 ## 2. 暴力解法与复杂度分析 ### 2.1 朴素DFS实现 最直观的做法是对每个节点执行一次DFS/BFS遍历 python def brute_force(tree): n len(tree) res [0]*n for u in range(n): visited [False]*n stack [(u,0)] while stack: node, dist stack.pop() visited[node] True res[u] dist for v in tree[node]: if not visited[v]: stack.append((v, dist1)) return res这个实现的时间复杂度是O(n²)当n1e5时需要1e10次操作显然不可行。2.2 树形结构的特殊性质观察到树是无向无环连通图具有以下关键性质任意两点间有且只有一条简单路径移除任意边会将树分成两个连通分量可以选取任意节点作为根节点转化为有根树这些性质提示我们可以利用动态规划来避免重复计算。3. 优化解法二次扫描动态规划3.1 第一次DFS后序遍历统计子树信息首先任选一个根节点通常选0号节点定义count[u]: 以u为根的子树节点数res[u]: u到其子树所有节点的距离和第一次DFS从根节点开始后序遍历def dfs1(u, parent): count[u] 1 res[u] 0 for v in tree[u]: if v ! parent: dfs1(v, u) count[u] count[v] res[u] res[v] count[v]关键点解释count[v]表示子树v的大小res[v]是v到其子树节点的距离和从v到u的每条边会被子树v的所有节点各走一次所以增加count[v]3.2 第二次DFS前序遍历推导全局解定义ans[u]为u到所有节点的距离和。对于根节点root显然ans[root]res[root]。对于其他节点u其父节点为p有状态转移方程ans[u] ans[p] - count[u] (n - count[u])推导过程从p切换到u时u的子树节点距离都-1共count[u]个其他节点距离都1共n-count[u]个实现代码def dfs2(u, parent): for v in tree[u]: if v ! parent: ans[v] ans[u] - count[v] (n - count[v]) dfs2(v, u)3.3 完整算法实现def tree_distances(tree): n len(tree) count [0]*n res [0]*n ans [0]*n def dfs1(u, parent): count[u] 1 for v in tree[u]: if v ! parent: dfs1(v, u) count[u] count[v] res[u] res[v] count[v] def dfs2(u, parent): for v in tree[u]: if v ! parent: ans[v] ans[u] - count[v] (n - count[v]) dfs2(v, u) dfs1(0, -1) ans[0] res[0] dfs2(0, -1) return ans4. 复杂度分析与正确性验证4.1 时间复杂度两次DFS遍历每个节点访问一次每个边被访问两次无向边总时间复杂度O(n)4.2 空间复杂度count/res/ans数组O(n)递归栈最坏情况O(n)退化成链总空间复杂度O(n)4.3 边界情况测试单节点树返回[0]链状树如0-1-2-3应返回[3,2,2,3]星型树中心节点距离和最小完全二叉树验证对称性5. 实际应用与变种问题5.1 应用场景案例网络监控中心选址选择到所有节点距离和最小的点部署监控服务电商仓储优化计算仓库到所有配送点的总距离社交网络分析找出关系网中最中心的人物5.2 常见变种题型加权树边带有权重计算加权距离和带有点权的树考虑节点权重的影响动态树支持边的增删操作找出距离和最小的k个节点6. 调试技巧与常见错误6.1 典型Debug场景忘记处理父节点导致循环调用# 错误写法 for v in tree[u]: dfs1(v, u) # 缺少parent判断 # 正确写法 for v in tree[u]: if v ! parent: dfs1(v, u)状态转移公式错误混淆count和res的含义忘记n-count[v]的部分6.2 验证技巧小规模测试手动计算n3,4的情况对称性验证对称树的结果应对称极值验证链状树端点值应为最大关键提示在竞赛中遇到类似问题建议先用小样例验证状态转移方程的正确性再处理大规模数据。我曾经因为直接写大数组导致RE浪费半小时。7. 算法优化与扩展思路7.1 空间优化版本对于极端大n的情况如1e6可以省去res数组def dfs1(u, parent): count[u] 1 total 0 for v in tree[u]: if v ! parent: total dfs1(v, u) count[u] count[v] ans[u] total return total count[u]7.2 非递归实现使用栈模拟递归避免爆栈def dfs1_iterative(root): stack [(root, -1, False)] while stack: u, parent, visited stack.pop() if not visited: stack.append((u, parent, True)) for v in reversed(tree[u]): if v ! parent: stack.append((v, u, False)) else: count[u] 1 res[u] 0 for v in tree[u]: if v ! parent: count[u] count[v] res[u] res[v] count[v]7.3 多叉树处理当子树数量不定时需要动态处理子节点for children in tree[u]: for v in children: if v ! parent: ...这个树形DP问题的核心在于发现父子节点间的递推关系。通过两次扫描我们巧妙地将O(n²)问题转化为O(n)解法。掌握这种思路后可以解决LeetCode 310、834等一系列相似问题。在实际编码时建议先画出树结构手动推导小样例再抽象出状态转移方程。记住树形DP的要点是合理设计状态利用子树信息推导全局解。
企业数字化 ERP 产品动态
相关推荐
S7-1500模拟量输出模块AQ 4xU/I ST安装与调试指南 简介:这份设备手册面向工业自动化领域的工程技术人员、系统集成商与运维人员,聚焦西门子 SIMATIC S7-1500/ET 200MP 系列模拟量输出模块 AQ 4xU/I ST(6ES7532-5HD00-0AB0)的工程应用,帮助读者解决模块选型、接线、参数… · 2026/11/6 10:28:24
Linux入门实战:从黑屏恐惧到命令熟练的完整指南 简介:这份资源是面向高校计算机及相关专业学生的操作系统课程实验报告,聚焦Linux用户接口与编程界面,帮助初学者从命令行操作过渡到C程序与Shell脚本的编写运行。内容覆盖字符界面常用命令(ls、uname、man、pwd、mkdir、rm等&… · 2026/11/6 10:28:24
悬臂梁变形分析Python实现:解析法与有限差分法对比 简介:面向具备一定Python编程能力与材料力学基础的高校学生、科研人员及工程技术人员,这份资源聚焦悬臂梁在受力条件下的变形数值模拟,围绕挠度、转角、弯矩与剪力的计算展开,将力学模型构建、微分方程求解与编程仿真结合起来&… · 2026/11/6 10:28:24
电工证怎样领取补贴 内部消息揭秘实操考试通关秘诀 电工证怎样领取补贴 内部消息揭秘实操考试通关秘诀 实操考试心里没底怕挂科,这事儿我懂,我也经历过。去年在濮阳一家培训机构报名考电工证,一听说要实操,整个人都不淡定了。说实话,现在电工证含金量不低,但要是考不过,等于白搭钱、白费时间。不过,内… · 2026/11/6 22:15:02
蚌埠电工证怎么报名官方回应来了 工地太忙根本没时间复习考试 蚌埠电工证怎么报名官方回应来了 工地太忙根本没时间复习考试 工地太忙根本没时间复习考试,这几乎是所有一线电工的共同困扰。但你知道吗? 河南省安全生产监督管理局 近期官方回应,2024年特种作业人员培训考试安排已明确, 蚌埠电工证怎么报名… · 2026/11/6 22:15:02
孝感建筑电工证办理流程全攻略:实操考试心里没底怕挂科?看这里就懂 孝感建筑电工证办理流程全攻略:实操考试心里没底怕挂科?看这里就懂 你是不是也在为【孝感建筑电工证办理】发愁?实操考试心里没底怕挂科?别急,这篇文章就是为你量身定制的,教你一步步搞定证书, 全国通用 ,而且还能查证,真正靠谱!… · 2026/11/6 22:15:02
低压电工证最高多少伏保姆级教程:别再被中介坑了,教你一招搞定报名 低压电工证最高多少伏保姆级教程:别再被中介坑了,教你一招搞定报名 你是不是也遇到过这种情况?想考低压电工证,却不知道去哪报名,生怕被中介坑了钱还拿不到证?别慌,这篇保姆级教程专门为你准备,从报考流程到考试范围,再到证书的执业范围,我手把手教… · 2026/11/6 22:15:02
黔南电工证怎么考内部消息全公开 学历不高怕报不上名别慌 黔南电工证怎么考内部消息全公开 学历不高怕报不上名别慌 你是不是也这样,想着自己学历不高,连电工证都怕报不上名?别急,我来告诉你 黔南电工证怎么考 的 内部消息 ,帮你少走弯路,顺利拿到证。… · 2026/11/6 22:14:02
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:27:59
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 10:29:23
三菱PLC数据采集到数据库的时序设计:Python+MC协议实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 1:02:11
ASIC主模式RTL设计:状态机与三态驱动的流片级实现 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 1:02:11
STM32嵌入式C++开发:GDB调试与Renode仿真实战指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 1:02:11
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:27:59
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 10:29:23