"世界树上找米库"是一个典型的树结构算法问题,题目要求在一棵无向树中找出所有满足特定条件的中心节点(米库点)。这类问题在实际应用中很常见,比如网络拓扑中的关键节点识别、物流配送中心的选址优化等场景。
问题的核心在于:给定一棵具有n个节点的树(无向无环图),我们需要找到所有非叶子节点中距离最近叶子节点最远的那些节点。这些节点可以理解为树的"中心点",因为它们到最外围叶子的距离最大。
提示:在树结构中,叶子节点是指度数为1的节点(即只连接一条边的节点),而非叶子节点则连接两条或更多边。
首先我们需要明确几个关键概念:
解决这个问题的关键在于如何高效计算每个非叶子节点到最近叶子节点的距离。我们采用了一种基于BFS的多源最短路径算法,具体步骤如下:
初始化阶段:
BFS遍历阶段:
结果收集阶段:
这种方法的优势在于:
java复制BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
int T = Integer.parseInt(br.readLine().trim()); // 读取测试用例数量
while (T-- > 0) {
int n = Integer.parseInt(br.readLine().trim()); // 读取节点数
// 初始化邻接表
List<Integer>[] adj = new ArrayList[n + 1];
for (int i = 1; i <= n; i++) {
adj[i] = new ArrayList<>();
}
// 初始化度数数组
int[] deg = new int[n + 1];
// 构建树结构
for (int i = 0; i < n - 1; i++) {
String[] edge = br.readLine().trim().split("\\s+");
int u = Integer.parseInt(edge[0]);
int v = Integer.parseInt(edge[1]);
adj[u].add(v);
adj[v].add(u);
deg[u]++;
deg[v]++;
}
这段代码完成了以下工作:
注意:邻接表使用ArrayList数组实现,索引从1开始到n,与节点编号对应
java复制// 初始化距离数组
int[] dist = new int[n + 1];
Arrays.fill(dist, -1);
Queue<Integer> queue = new LinkedList<>();
// 将所有叶子节点加入队列
for (int i = 1; i <= n; i++) {
if (deg[i] == 1) {
dist[i] = 0;
queue.add(i);
}
}
// 执行BFS
while (!queue.isEmpty()) {
int u = queue.poll();
for (int v : adj[u]) {
if (dist[v] == -1) {
dist[v] = dist[u] + 1;
queue.add(v);
}
}
}
这部分代码实现了算法的核心逻辑:
java复制// 找出最大距离
int maxDist = -1;
for (int i = 1; i <= n; i++) {
if (deg[i] > 1) { // 只考虑非叶子节点
maxDist = Math.max(maxDist, dist[i]);
}
}
// 收集所有米库点
List<Integer> mikuPoints = new ArrayList<>();
for (int i = 1; i <= n; i++) {
if (deg[i] > 1 && dist[i] == maxDist) {
mikuPoints.add(i);
}
}
// 输出结果
out.println(mikuPoints.size());
for (int i = 0; i < mikuPoints.size(); i++) {
out.print(mikuPoints.get(i) + (i == mikuPoints.size() - 1 ? "" : " "));
}
out.println();
结果处理阶段:
该算法的时间复杂度可以分为几个部分:
总体时间复杂度为O(n),对于树结构来说是最优的,因为必须至少访问每个节点一次。
空间消耗主要来自:
总体空间复杂度为O(n),同样是最优的。
虽然当前算法已经很高效,但在特定场景下还可以考虑:
数组越界:
错误的最大距离计算:
输出格式错误:
小规模测试:
打印中间结果:
java复制System.err.println("Debug: dist array - " + Arrays.toString(dist));
打印距离数组帮助验证BFS是否正确执行
边界测试:
IO优化:
对象复用:
数据结构选择:
这个算法可以应用于:
与Dijkstra比较:
与Floyd-Warshall比较:
与树直径算法比较: