【競プロ典型90問】「003 - Longest Circular Road(★4)」解法
Free-PhotosによるPixabayからの画像

問題

003 - Longest Circular Road(★4)

ポイント

この問題で与えられているデータは木構造をしています。
※木構造のデータについて、詳細を知りたい方は下記記事が参考になると思います。
ITの基礎知識|ITパスポート・基本情報 - 木構造

「同じ道を2度通らずにある都市から同じ都市に戻ってくる経路における、通った道の本数」を
最大にするには、
 ①木の直径を求める
 ②木の直径となっている都市 u と都市 v を双方向に結ぶ道路を 1 本新設する
 ③木の直径+1を答えとして出力する
といった手順を踏めば良いです。

木の直径の求め方ですが、はじめにどこの都市からでも良いので深さ優先探索(BFS)を行い、
その後最も遠かった都市から再度BFSを行うと求めることができます。
※BFSについては下記記事の解説が分かりやすいです。いずれこのブログでも解説記事書きます!
【AtCoder】Pythonで使いこなす深さ優先探索・幅優先探索

何故そうなるのかを簡単に説明します。
※数学的証明とは程遠いのですが、何となくイメージだけでも掴んでいただければと!

以下の都市u,vが直径を成している木を考えます。

そこで、ある都市xからBFSをし、一番遠い都市 v にたどり着きました。

その後、都市vからBFSを行うと直径の端である都市uにたどり着くという寸法です。

以上を踏まえ、実装したコードがこちらです。

コード

def main():
    import sys
    sys.setrecursionlimit(10 ** 9)
    input = sys.stdin.readline

    N = int(input())
    edges = [[] for _ in range(N+1)]
    for _ in range(N-1):
        a, b = map(int, input().split())
        edges[a].append(b)
        edges[b].append(a)

    dist = [0] * (N+1)

    def dfs(x, last):
        for to in edges[x]:
            if to == last:
                continue
            dist[to] = dist[x] + 1
            dfs(to, x)

    dfs(1, -1)  # スタートは何でも良いのでdfs1回目
    max_dist = max(dist)
    max_dist_node = dist.index(max_dist)

    # dfs2回目
    dist = [0] * (N+1)
    dfs(max_dist_node, -1)
    print(max(dist) + 1)  # 直径 + 1 を出力


if __name__ == '__main__':
    main()
おすすめの記事