差分
このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン前のリビジョン | 次のリビジョン両方とも次のリビジョン | ||
programming_algorithm:graph_theory:lowest_common_ancestor [2019/12/26] – [ダブリング] ikatakos | programming_algorithm:graph_theory:lowest_common_ancestor [2020/02/06] – [ダブリング] ikatakos | ||
---|---|---|---|
行 127: | 行 127: | ||
$k=0$ までやったら、$a, | $k=0$ までやったら、$a, | ||
+ | |||
+ | ++++ 実装例(Python) | | ||
+ | <sxh python> | ||
+ | class LcaDoubling: | ||
+ | """ | ||
+ | links[v] = { (u, w), (u, w), ... } (u: | ||
+ | というグラフ情報から、ダブリングによるLCAを構築。 | ||
+ | 任意の2頂点のLCAおよび距離を取得できるようにする | ||
+ | """ | ||
+ | depths: list | ||
+ | distances: list | ||
+ | ancestors: list | ||
+ | |||
+ | def __init__(self, | ||
+ | self.depths = [-1] * n | ||
+ | self.distances = [-1] * n | ||
+ | prev_ancestors = self._init_dfs(n, | ||
+ | self.ancestors = [prev_ancestors] | ||
+ | max_depth = max(self.depths) | ||
+ | d = 1 | ||
+ | while d < max_depth: | ||
+ | next_ancestors = [prev_ancestors[prev_ancestors[v]] for v in range(n)] | ||
+ | self.ancestors.append(next_ancestors) | ||
+ | d <<= 1 | ||
+ | prev_ancestors = next_ancestors | ||
+ | |||
+ | def _init_dfs(self, | ||
+ | q = [(root, -1, 0, 0)] | ||
+ | direct_ancestors = [0] * n | ||
+ | while q: | ||
+ | v, p, dep, dist = q.pop() | ||
+ | direct_ancestors[v] = p | ||
+ | self.depths[v] = dep | ||
+ | self.distances[v] = dist | ||
+ | q.extend((u, | ||
+ | return direct_ancestors | ||
+ | |||
+ | def lca(self, u, v): | ||
+ | du, dv = self.depths[u], | ||
+ | if du > dv: | ||
+ | u, v = v, u | ||
+ | du, dv = dv, du | ||
+ | tu = u | ||
+ | tv = self.upstream(v, | ||
+ | if u == tv: | ||
+ | return u | ||
+ | for k in range(du.bit_length() - 1, -1, -1): | ||
+ | mu = self.ancestors[k][tu] | ||
+ | mv = self.ancestors[k][tv] | ||
+ | if mu != mv: | ||
+ | tu = mu | ||
+ | tv = mv | ||
+ | lca = self.ancestors[0][tu] | ||
+ | assert lca == self.ancestors[0][tv] | ||
+ | return lca | ||
+ | |||
+ | def get_distance(self, | ||
+ | lca = self.lca(u, v) | ||
+ | return self.distances[u] + self.distances[v] - 2 * self.distances[lca] | ||
+ | |||
+ | def upstream(self, | ||
+ | i = 0 | ||
+ | while k: | ||
+ | if k & 1: | ||
+ | v = self.ancestors[i][v] | ||
+ | k >>= 1 | ||
+ | i += 1 | ||
+ | return v | ||
+ | </ | ||
+ | ++++ | ||
===== バリエーション ===== | ===== バリエーション ===== |