换根法(Rerooting)算法详解
📅 2026/7/27 1:51:50
👁️ 次浏览
1. 什么是换根法换根法Rerooting是一种在树形数据结构通常是树或图上解决动态规划问题的算法技巧。其核心思想是先以树中任意一个节点为根进行一次深度优先搜索DFS计算出以该节点为根的子树相关的答案然后通过第二次 DFS利用已计算出的信息高效地将根节点“换”到其他节点并计算出以新节点为根时的答案。这种方法避免了为每个节点作为根都进行一次完整的 O(n) 遍历从而将总时间复杂度从 O(n²) 优化到 O(n)。2. 算法思想与步骤2.1 第一次 DFS预处理自底向上任选一个节点通常为节点 0 或 1作为初始根进行一次后序遍历Post-order Traversal。计算每个节点只考虑其子树时的状态值。例如子树大小、子树节点权值和、子树中最长路径等。将子节点的信息“贡献”给父节点完成自底向上的信息聚合。这一步结束后我们得到了以初始根节点为根时所有节点的“子树信息”。2.2 第二次 DFS换根自顶向下从初始根节点开始进行前序遍历Pre-order Traversal。当从父节点u遍历到子节点v时我们已知以u为根时整棵树的信息。现在要将根从u“换”到v。这意味着节点v的子树相对于原根保持不变。节点u及其除v以外的其他子树将变成节点v的一棵新子树。利用第一次 DFS 计算出的“子树信息”我们可以 O(1) 或 O(子节点数) 地计算出以v为根时所需的信息。将计算出的以v为根的答案记录下来然后递归地对v的子节点进行同样的换根操作。3. 经典应用场景求树中每个节点到其他所有节点的距离之和LeetCode 310. Minimum Height Trees 的变体或直接求“距离和”。求树中以每个节点为根时的子树大小/权值和。求树中以每个节点为根时的最长路径树的直径。求树中以每个节点为根时满足某种条件如颜色、奇偶性的节点个数。在加权树上求每个节点到其他节点的最大/最小代价。4. 代码模板C#include vector #include functional using namespace std; /** 换根法通用模板框架C 假设问题求以每个节点为根时其子树节点值的和节点值默认为1即求子树大小。 */ vectorint rerooting(int n, vectorvectorint edges) { // 建图 vectorvectorint graph(n); for (auto e : edges) { int u e[0], v e[1]; graph[u].push_back(v); graph[v].push_back(u); } // 第一次DFS后序遍历计算子树信息 dp_sub vectorint dp_sub(n, 0); // dp_sub[u] 表示以u为根的子树节点和 functionvoid(int, int) dfs1 [](int u, int parent) { dp_sub[u] 1; // 节点自身 for (int v : graph[u]) { if (v parent) continue; dfs1(v, u); dp_sub[u] dp_sub[v]; // 累加子树的贡献 } }; dfs1(0, -1); // 假设以0为初始根 // 第二次DFS前序遍历进行换根计算最终答案 ans vectorint ans(n, 0); // ans[u] 表示以u为根时整棵树的节点和 ans[0] dp_sub[0]; // 初始根的结果就是其子树和即整棵树 functionvoid(int, int) dfs2 [](int u, int parent) { for (int v : graph[u]) { if (v parent) continue; // 将根从 u 换到 v // 1. 从 u 的贡献中移除 v 的子树贡献 // 2. 将 u及其剩余部分作为 v 的新子树贡献加给 v // 对于“子树节点和”问题 // ans[v] dp_sub[v] (ans[u] - dp_sub[v]) // 化简后ans[v] ans[u] // 但通用情况需要更复杂的转移这里展示框架 ans[v] dp_sub[v] (ans[u] - dp_sub[v]); dfs2(v, u); } }; dfs2(0, -1); return ans; } // 示例一棵4个节点的链 0-1-2-3 int main() { int n 4; vectorvectorint edges {{0,1},{1,2},{2,3}}; vectorint result rerooting(n, edges); // 输出每个节点为根时的子树节点和实际上对于链就是节点数4 for (int val : result) { printf(%d , val); } return 0; }5. 关键点与注意事项状态定义明确第一次 DFS 要计算的“子树信息”是什么以及如何从子节点转移到父节点。换根转移方程这是最核心的部分。需要推导出当根从父节点u换到子节点v时如何利用已知的dp_sub和ans[u]快速计算出ans[v]。初始化注意初始根节点答案的初始化。避免重复计算在第二次 DFS 中当计算子节点v的答案时要确保使用的父节点u的答案是最新的即已经完成了换根到u的计算。复杂度两次 DFS 都是 O(n)总时间复杂度 O(n)空间复杂度 O(n)。6. 实战例题解析LeetCode 310. Minimum Height Trees问题可以转化为对于无向图树求以每个节点为根时的树高然后找出最小高度对应的根节点集合。使用换根法第一次 DFS 计算每个节点向下的最大高度和次大高度用于换根时当最深的路径经过当前子节点时需要使用次大高度。第二次 DFS 进行换根计算每个节点向上的高度即从父节点方向来的最长路径然后结合向下的高度得到以该节点为根时的总高度。此处可展开详细代码限于篇幅省略7. 总结换根法是一种非常高效的树形 DP 优化技巧将“为每个根计算答案”的问题从 O(n²) 优化到 O(n)。掌握其核心的两次 DFS 流程自底向上预处理 自顶向下换根以及状态转移方程的推导是解决此类问题的关键。在 LeetCode、Codeforces 等算法竞赛中换根法是解决树形问题的必备高级技能之一。
1. 项目概述:为什么我们需要自己动手实现高精度运算?在C的日常开发中,无论是处理金融数据、科学计算,还是游戏中的物理模拟,我们常常会遇到一个看似简单却令人头疼的问题:内置的整数类型(如int,…
📅 2026/7/27 1:51:50
1. 项目概述:为什么2024年还要深挖C STL? 最近在带新人做项目,发现一个挺有意思的现象:很多刚接触C的朋友,一上来就急着学各种框架、搞并发、玩模板元编程,但一让他们用 std::vector 实现个动态数组&…
📅 2026/7/27 1:51:50
1. 项目概述:为什么需要同时掌握Lua元表和C/C权限处理?如果你正在开发一个游戏引擎、嵌入式脚本系统,或者任何需要将高性能的C/C核心与灵活、热更新的Lua脚本结合起来的项目,那么你迟早会碰到两个核心难题:如何在Lua中…
📅 2026/7/27 1:51:50
1. 项目背景与核心价值无人机3D路径规划是当前智能飞行器领域的关键技术挑战。在复杂三维环境中,无人机需要避开建筑物、山体等障碍物,同时满足飞行时间、能耗、安全性等多重约束条件。传统单目标优化算法往往难以平衡这些相互冲突的指标,这正…
📅 2026/7/27 3:00:09
1. 问题现象与背景解析当你在Windows系统运行某些软件时,突然弹出"无法启动此程序,因为计算机中丢失mfc140u.dll"的错误提示,这种情况通常发生在以下场景:安装新版本Visual C运行库后旧版本被覆盖误删系统关键文件使用绿…
📅 2026/7/27 3:00:09
1. Windows开机自启动应用配置指南每次开机后手动点击那些常用软件的图标是不是很烦?作为Windows系统管理员,我经常需要帮同事配置各种办公软件的开机自启动。今天就来分享几种可靠的方法,让你的常用软件在开机时自动运行。2. 实现方案对比与…
📅 2026/7/27 3:00:09
1. 项目概述:为什么我们需要线程安全队列?在C的多线程编程世界里,线程安全队列(Thread-Safe Queue)是一个绕不开的经典组件。它不仅仅是数据结构,更是协调不同线程工作、实现数据安全流转的“交通枢纽”。想…
📅 2026/7/27 3:00:09
1. 项目概述:用Matlab诊断植物病害的跨界实践去年夏天,我家阳台的番茄叶片突然出现褐色斑点,作为理工科背景的植物杀手,我决定用Matlab的图像处理工具箱给植物做次"CT扫描"。这个看似跨界的需求,其实完美契合…
📅 2026/7/27 3:00:09
搞接地工程,最怕啥?怕测不准。一不准,验收过不了,钱还得自己掏腰包补打地桩。这篇就教你咋用GEO1022型土壤电阻率检测仪,把数据测得明明白白,不交智商税。我干这行十年了,见过太多新手瞎搞。拿着仪器随便插两根棒子,读数跳两下就完事。结果呢?验收时候监理一眼看穿,让…
📅 2026/7/27 2:58:56
现象在 WezTerm 终端中,包含中文路径的文本(如标签页标题、Shell 提示符、路径补全)中,某些汉字时而渲染为日文字形,时而显示为简体中文(中国大陆)字形。以「径」字为例,日文写法右侧…
📅 2026/7/27 0:00:07
这个问题看似在寻找一个答案,实际上是在寻找一种“值得继续投入的方向感”。很多人在问:
“人生有什么意义?”
深层可能是在问:
我现在做的事情值得吗?我的努力有没有价值?我的存在是不是重要?未…
📅 2026/7/27 0:00:07
1. 为什么MoE架构让大模型参数量翻倍却不增加推理成本?去年我在部署一个千亿参数大语言模型时,首次接触到混合专家模型(Mixture of Experts,简称MoE)架构。当时最让我震惊的是,这种架构的模型参数量可以达到…
📅 2026/7/27 0:00:07
更多请点击:
https://codechina.net
第一章:AI帮助理解数学概念 人工智能正以前所未有的方式重塑数学学习的路径。通过自然语言处理与符号计算的深度融合,AI不仅能解析抽象定义,还能将定理、证明和几何直觉转化为可交互、可验证的…
📅 2026/7/27 1:11:21
1. 项目背景与核心价值去年参与的一个短剧项目让我深刻体会到传统创作流程的痛点:编剧团队花了三周打磨剧本,角色设计反复修改了七版,最后成片时又因为演员档期问题不得不临时调整分镜。这种低效的创作模式在快节奏的内容行业越来越难以为继。…
📅 2026/7/27 1:11:21
remix-i18next TypeScript类型安全实践:确保翻译键与类型定义同步 【免费下载链接】remix-i18next The easiest way to translate your React Router framework mode apps 项目地址: https://gitcode.com/gh_mirrors/re/remix-i18next
在开发多语言应用时&am…
📅 2026/7/27 1:11:21
目录
第一步:选对模板,省心一半
第二步:打开扫码点餐功能
开启功能按钮
桌台管理与桌码生成
第三步:个性化设计,打造品牌感
调整点餐页面
设置点餐规则 你还在让顾客站着排队点餐吗?2025年ÿ…
📅 2026/7/26 7:10:22
在业务中快速构建一个能理解私有文档、准确回答专业问题的智能助手,是很多开发团队面临的共同挑战。传统方案往往需要从零开始搭建复杂的 RAG(检索增强生成)系统,涉及文档解析、向量化、检索、大模型调用等多个环节,整…
📅 2026/7/26 17:10:53
FAE放射组学分析工具:医学影像特征探索的完整解决方案 【免费下载链接】FAE FeAture Explorer 项目地址: https://gitcode.com/gh_mirrors/fae/FAE
你是否曾经面对海量医学影像数据感到无从下手?想要从CT、MRI等影像中提取有价值的定量特征&#…
📅 2026/7/26 5:10:17