본문 바로가기
알고리즘 풀기

[백준] 1967 트리의 지름 python3

by 쏘야.yap 2020. 3. 10.
728x90

문제 : https://www.acmicpc.net/problem/1967

 

1967번: 트리의 지름

파일의 첫 번째 줄은 노드의 개수 n(1 ≤ n ≤ 10,000)이다. 둘째 줄부터 n번째 줄까지 각 간선에 대한 정보가 들어온다. 간선에 대한 정보는 세 개의 정수로 이루어져 있다. 첫 번째 정수는 간선이 연결하는 두 노드 중 부모 노드의 번호를 나타내고, 두 번째 정수는 자식 노드를, 세 번째 정수는 간선의 가중치를 나타낸다. 간선에 대한 정보는 부모 노드의 번호가 작은 것이 먼저 입력되고, 부모 노드의 번호가 같으면 자식 노드의 번호가 작은 것이 먼

www.acmicpc.net

 

python3 코드

# 임의의 노드 A에서 가장 먼 노드 B는 반드시 이 트리의 지름을 구성하게 된다.
from collections import deque


def find_furthest_node(start):
    max_index = start
    max_value = 0

    queue = deque()
    queue.append(start)

    distances = [-1 for _ in range(n+1)]
    distances[start] = 0

    # bfs
    while queue:
        # 노드를 가져와서
        current = queue.popleft()
        # 그 이웃들을 찾고
        neghibors = graph[current]
        # 그 이웃들에 대하여
        for neghibor in neghibors.keys():
            # 방문한 적 없는 노드면
            if distances[neghibor] == -1:
                # 거리를 더하고
                distances[neghibor] = distances[current] + neghibors[neghibor]
                # 큐에 그 이웃을 추가
                queue.append(neghibor)
                # 최댓값인지 판별
                if max_value < distances[neghibor]:
                    max_index = neghibor
                    max_value = distances[neghibor]

    return (max_index, max_value)


n = int(input())
graph = {}
for i in range(1, n+1):
    graph[i] = {}

# 그래프 그리기
for _ in range(n-1):
    v, u, weight = map(int, input().split(" "))
    graph[v][u] = weight
    graph[u][v] = weight

# 노드 1에서 가장 먼 노드 B 찾기
v = find_furthest_node(1)
u = find_furthest_node(v[0])

print(u[1])

 

풀이

트리의 지름을 구하는 공식을 알면 bfs로 간단히 풀 수 있는 문제다.

임의의 노드A에서 가장 거리가 먼 노드B를 구하고, 이 노드B 에서 가장 거리가 먼 노드C를 구하면, 노드 B와 C사이의 거리가 트리의 지름이다.

 

따라서 거리를 저장하는 distance 리스트를 둔 뒤, bfs를 활용해서

  1. 임의의 노드(여기선 root)에서의 가장 거리가 먼 노드 B를 찾고
  2. 같은 로직으로 B에서 제일 먼 노드 C를 찾아서
  3. 그 사이 거리를 return 해준다.

증명

임의의 노드를 x, x에서 가장 먼 노드를 y, 트리의 지름을 이루는 노드를 각각 v u라고 정의하면, 다음과 같은 경우가 존재한다.

  1. x가 v 또는 u인 경우
  2. y가 v 또는 u인 경우
  3. x, y, v, u 가 서로 다른 경우

1, 2의 경우 공식은 올바르게 작동한다. 따라서 귀류법을 통해 3이 거짓임을 증명하여 공식이 옳음을 증명해보겠다.

 

경우3은 다음과 같이 나눌 수 있다.

경우3

a. x-y를 잇는 간선과 v-u를 잇는 간선이 겹치지 않는 경우

b. 두 간선이 서로 겹치는 경우

 

경우a는 성립하지 않는다. d(a, b) a-b간의 거리라고 할 때, 경우a에서는 d(x, y) < d(x, u) 혹은 d(x, v)이기 때문에 거짓이다.

경우a. d(x, u)가 더 멀다.

 

경우b를 다음과 같이 다시 그리고, 겹치는 노드를 t라고 정의해보자.

 

경우b

d(x, y) = d(x, t) + d(t, y) 이며, d(x, y)가 최댓값이 되기 위해서는 어떤 노드s에 대하여 항상 d(t, y) > d(t, s) 가 되어야 한다.

따라서 d(t, y) > d(t, v) 이고 d(t, y) > d(t, u) 이다.

하지만 이러면 d(v, u) = d(v, t) + d(t, u) 가 트리의 지름이 될 수 없기에 이 가설은 거짓이다.

 

'알고리즘 풀기' 카테고리의 다른 글

[백준] 3055 탈출 python3  (0) 2020.03.12
[백준] 2667 단지번호붙이기 python3  (0) 2020.03.10
[백준] 14501 퇴사 python3  (0) 2020.03.08
[백준] 2875 대회or인턴 python3  (0) 2020.02.29