[JLOI2009] 二叉樹問題
題目描述
如下圖所示的一棵二叉樹的深度、寬度及結點間距離分別為:
- 深度:
$4$
- 寬度:
$4$
- 結點 8 和 6 之間的距離:
$8$
- 結點 7 和 6 之間的距離:
$3$
其中寬度表示二叉樹上同一層最多的結點個數,節點 $u, v$
之間的距離表示從 $u$
到 $v$
的最短有向路徑上向根節點的邊數的兩倍加上向葉節點的邊數。
給定一顆以 1 號結點為根的二叉樹,請求出其深度、寬度和兩個指定節點 $x, y$
之間的距離。
輸入格式
第一行是一個整數,表示樹的結點個數 $n$
。
接下來 $n - 1$
行,每行兩個整數 $u, v$
,表示樹上存在一條連線 $u, v$
的邊。
最後一行有兩個整數 $x, y$
,表示求 $x, y$
之間的距離。
輸出格式
輸出三行,每行一個整數,依次表示二叉樹的深度、寬度和 $x, y$
之間的距離。
樣例 #1
樣例輸入 #1
10
1 2
1 3
2 4
2 5
3 6
3 7
5 8
5 9
6 10
8 6
樣例輸出 #1
4
4
8
提示
對於全部的測試點,保證 $1 \leq u, v, x, y \leq n \leq 100$
,且給出的是一棵樹。
解題思路
求樹的深度,就是求節點到根節點的距離最大值。
求樹的寬度,就是求同一深度節點(到根節點距離相同)的數量最大值。
Floyd演算法
計算任意兩點的最短路徑
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
graph[i][j] = MIN(graph[i][j], graph[i][k]+graph[k][j]);
}
}
}
計算透過k處,i節點到j節點的最短距離
AC程式碼
#include<bits/stdc++.h>
using namespace std;
#define MAX(a, b) ((a)<(b)?(b):(a))
#define MIN(a, b) ((a)<(b)?(a):(b))
int n;
int graph[100][100];
int main() {
cin >> n;
int u, v;
memset(graph, 0, sizeof(graph));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (i != j) graph[i][j] = INT_MAX/2;
}
}
for (int i = 0; i < n-1; i++) {
cin >> u >> v;
graph[u][v] = 1;
graph[v][u] = 2;
}
cin >> u >> v;
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
graph[i][j] = MIN(graph[i][j], graph[i][k]+graph[k][j]);
}
}
}
int depth = 0, width = 0, max = 0;
int d[100] = {0};
for (int i = 2; i <= n; i++) {
depth = MAX(graph[1][i], depth); // 列舉到根節點的深度
d[graph[1][i]]++; // 不同深度計數
}
for (int i = 1; i <= depth; i++) {
width = MAX(d[i], width); // 遍歷不同深度的節點數量,計算最大值
}
cout << depth+1 << endl; // 根節點深度為1
cout << width << endl;
cout << graph[u][v] << endl;
}