树中所有节点到其他节点的距离之和
给定一棵包含 n 个节点的无向连通树,我们需要计算每个节点到树中其他所有节点的距离之和。输入包括节点数 n 和边的列表 edges。
直接对每个节点运行 BFS 或 DFS 计算距离,时间复杂度会是 O(n²)。对于大规模数据,这显然不够高效。我们可以利用动态规划(Dynamic Programming)结合两次深度优先搜索(DFS),将复杂度优化到 O(n)。这种方法通常被称为'换根 DP'(Re-rooting DP)。
核心思路
整个过程分为两个阶段:
- 自底向上(后序遍历):以任意节点(比如 0 号节点)为根,计算每个子树的大小(size)以及该节点在其子树内的距离总和(distance)。这一步能算出根节点的答案,同时为后续推导子节点答案提供基础数据。
- 自顶向下(前序遍历):利用父节点的信息推导子节点的答案。当我们从父节点移动到子节点时,除了子树内部的距离不变外,其他所有节点到新根的距离都会增加 1。公式可以简化为:
新根距离和 = 旧根距离和 - 子树大小 + (总节点数 - 子树大小)。
实现细节
Go 语言实现
Go 版本利用切片构建邻接表,逻辑清晰且内存管理由 GC 处理。
package main
import "fmt"
var N int = 30001
var size [30001]int
var distance [30001]int
func sumOfDistancesInTree(n int, edges [][]int) []int {
graph := make([][]int, n)
for i := range graph {
graph[i] = []int{}
}
for _, edge := range edges {
u := edge[0]
v := edge[1]
graph[u] = append(graph[u], v)
graph[v] = append(graph[v], u)
}
collect(0, -1, graph)
ans := make([]int, n)
setAns(0, -1, , graph, ans)
ans
}
{
size[cur] =
distance[cur] =
_, next := graph[cur] {
next != father {
collect(next, cur, graph)
distance[cur] += distance[next] + size[next]
size[cur] += size[next]
}
}
}
{
ans[cur] = distance[cur] + upDistance
_, next := graph[cur] {
next != father {
setAns(next, cur, ans[cur]-distance[next]+size[]-(size[next]<<), graph, ans)
}
}
}
{
n :=
edges := [][]{{, }, {, }, {, }, {, }, {, }}
result := sumOfDistancesInTree(n, edges)
fmt.Println(result)
}


