木
投稿者:CarpDay.icon
1. 木の直径
(1) 定義
木に存在する2つのノードの距離の最大値.最も離れている2点間の距離
「距離=パス上の枝の本数」でも,枝に長さがあって「距離=パス上の枝の距離の合計」でもOK
(2) アルゴリズム
任意の点$ s を選ぶ
点$ s から BFS/DFS によって、最も遠くにある点$ u を探索する
点$ u から BFS/DFS によって、最も遠くにある点 $ v を探索する
点$ uから点$ vまでの距離が直径
計算量$ O(N)
(3) コード例
code: python
from collections import defaultdict
from collections import deque
def tree_distance(n: int, adj: defaultdict, r: int) -> tuple:
d = 0 * (n + 1) # rからの距離.1-index checked = False * (n + 1) # チェック済み判定.1-index q = deque(r) # これから探索する点を格納するキュー max_d, max_v = 0, r # rからの最大距離.最大距離の点
while q:
v = q.popleft()
for u, c in adjv: # 隣接点,(v, u)の距離 q.append(u)
return max_v, max_d, d # rから最も遠い点,rから最も遠い距離,距離(リスト)
def tree_diameter(n: int, adj: defaultdict):
max_v1, max_d1, d1 = tree_distance(N, adj, 1)
max_v2, max_d2, d2 = tree_distance(N, adj, max_v1)
return max_d2
N = 4
adj = defaultdict(list)
for a, b, c in ABC:
adja.append((b, c)) # (隣接点,距離) print(tree_diameter(N, adj)) # 直径は 点3,1,4を通る 7 2. 木の半径
(1) 定義
他のノードまでの距離の最大値の最小値
直径が偶数のとき,半径=直径/2.直径が奇数のとき,半径=(直径+1)/2
「距離=パス上の枝の本数」でも,枝に長さがあって「距離=パス上の枝の距離の合計」でもOK
3. 木の中心
(1) 定義
最も遠い他の点への距離が半径と一致する点.複数存在する場合もある.
「距離=パス上の枝の本数」でも,枝に長さがあって「距離=パス上の枝の距離の合計」でもOK
(2) アルゴリズム
任意の点$ s を選ぶ
点$ s から BFS/DFS によって、各点$ uからその子孫までの距離の最大値$ d_uを計算する
$ v \leftarrow sとして,以下のループ開始
$ d_v = 半径なら,点$ vが中心.ループを抜ける.
点 $ vの子のうち,$ d_uが最大となる点を$ uとする.$ v \leftarrow u
計算量$ O(N)
(3) コード例
TBA
4. 木の重心
(1) 定義
木に存在する点(とその点に隣接している枝)を削除したとき,作成されるすべての部分木の点数が,元の点数の半分以下となる点
(2) アルゴリズム
木の中心のアルゴリズムと考え方は同じ
ある点$ s から BFS/DFS によって、各点$ u,およびその子孫に存在する点数$ n_uを計算する
$ v \leftarrow sとして,以下のループ開始
$ n_v <= 木の点数/2なら,点$ vが中心.ループを抜ける.
点 $ vの子のうち,$ n_uが最大となる点を$ uとする.$ v \leftarrow u
計算量$ O(N)
(3) コード例
TBA