📅  最后修改于: 2023-12-03 15:28:42.429000             🧑  作者: Mango
给定一个 N 个节点的树,每个节点有一个权重值。定义树的重心为树上某个节点,如果将该节点删除后,最大的连通块不超过 N/2,我们称该节点为树的重心。在给定的树中找到树的所有重心。
第一行输入一个整数 $N$,表示树的节点数。
接下来 $N$ 行,每行输入两个整数 $u$ 和 $w$,表示节点的编号和权重值。
接下来 $N-1$ 行,每行输入两个整数 $u$ 和 $v$,表示树上的一条边。
输出一个或多个整数,表示树的重心的编号,按编号升序排列。
输入:
5
1 1
2 1
3 1
4 1
5 1
1 2
2 3
2 4
1 5
输出:
2
题目要求找到树的重心,而重心有一个重要的性质:树的重心是树上最深的叶子节点的父节点。
因此,我们可以使用 DFS 计算每个节点的子树大小和最深叶子节点的深度。然后,我们可以使用 BFS 或 DFS 来查询树的重心,并将它们按升序排列输出。
以下是 Python 的实现:
from collections import deque
from typing import List, Tuple
def find_centroids(n: int, nodes: List[Tuple[int, int]], edges: List[Tuple[int, int]]) -> List[int]:
# Step 1: Build adjacency list to represent the tree
adj_list = [[] for _ in range(n)]
for u, v in edges:
adj_list[u-1].append(v-1)
adj_list[v-1].append(u-1)
# Step 2: Compute each node's subtree size and maximum depth
size, depth = [0] * n, [0] * n
def dfs(node, parent):
size[node] = 1
for child in adj_list[node]:
if child != parent:
dfs(child, node)
size[node] += size[child]
depth[node] = max(depth[node], depth[child]+1)
dfs(0, -1)
# Step 3: Find all centroids
q = deque([0])
while q:
node = q.popleft()
is_centroid = True
for child in adj_list[node]:
if size[child] > n // 2:
is_centroid = False
break
if is_centroid or node == 0:
yield node + 1
for child in adj_list[node]:
q.append(child)
这个算法的时间复杂度为 $O(N)$,其中 $N$ 是树的节点数。这是因为我们只需要遍历一遍树来计算每个节点的子树大小和深度,以及一遍 BFS 或 DFS 来查找树的重心。