木構造において2つの頂点間の最短経路を求める問題です。木は閉路がないため、任意の2頂点間には唯一の経路が存在します。BFS(幅優先探索)を使用して効率的に経路を探索します。
from typing import List, Dict
from collections import defaultdict, deque
import sys
class Solution:
def shortest_path_in_tree(self, n: int, x: int, y: int, edges: List[List[int]]) -> List[int]:
"""
木における2頂点間の最短経路を BFS で求める
"""
if not (1 <= n <= 100000):
raise ValueError("Invalid number of nodes")
if not (1 <= x <= n and 1 <= y <= n and x != y):
raise ValueError("Invalid start or end node")
if len(edges) != n - 1:
raise ValueError("Edges must contain exactly n-1 items")
graph: Dict[int, List[int]] = defaultdict(list)
for a, b in edges:
graph[a].append(b)
graph[b].append(a)
parent = [-1] * (n + 1)
parent[x] = 0
q = deque([x])
while q:
cur = q.popleft()
if cur == y:
break
for nxt in graph[cur]:
if parent[nxt] == -1:
parent[nxt] = cur
q.append(nxt)
path: List[int] = []
node = y
while node != 0:
path.append(node)
if node == x:
break
node = parent[node]
path.reverse()
return path
if __name__ == "__main__":
sys.setrecursionlimit(1 << 25)
N, X, Y = 6, 1, 6
edges = [[1,2],[1,3],[2,4],[2,5],[3,6]]
solver = Solution()
print(solver.shortest_path_in_tree(N, X, Y, edges))
頂点数、始点・終点、辺の数が適切かチェックします。木構造では辺の数は必ずn-1個である必要があります。
与えられた辺のリストから、各頂点に接続されている隣接頂点のリストを作成します。無向グラフなので双方向に追加します。
親ノードを記録する配列とBFS用のキューを初期化します。始点から探索を開始します。
キューから頂点を取り出し、その隣接頂点を探索します。未訪問の頂点があれば親を記録してキューに追加します。
現在の頂点が終点と一致した場合、BFSを終了します。木構造なので必ず終点に到達できます。
終点から始点まで親を辿って経路を復元し、最後に反転させて始点→終点の順序にします。
下のボタンを使ってBFSの動作を段階的に確認できます。
木は閉路がないため、任意の2頂点間に唯一の経路が存在します。これにより探索が効率的になります。
BFSは最短経路を保証し、親ノードの記録により経路復元が簡単になります。
各頂点を最大1回だけ訪問するため、時間計算量はO(n)と非常に効率的です。