코딩테스트/백준

[백준 1167] 트리의 지름 (Java) BFS버전

imachill7guy 2025. 3. 3. 20:05

https://www.acmicpc.net/problem/1167

트리의 지름

문제

트리의 지름이란, 트리에서 임의의 두 점 사이의 거리 중 가장 긴 것을 말한다. 트리의 지름을 구하는 프로그램을 작성하시오.

입력

트리가 입력으로 주어진다. 먼저 첫 번째 줄에서는 트리의 정점의 개수 V가 주어지고 (2 ≤ V ≤ 100,000)둘째 줄부터 V개의 줄에 걸쳐 간선의 정보가 다음과 같이 주어진다. 정점 번호는 1부터 V까지 매겨져 있다.

먼저 정점 번호가 주어지고, 이어서 연결된 간선의 정보를 의미하는 정수가 두 개씩 주어지는데, 하나는 정점번호, 다른 하나는 그 정점까지의 거리이다. 예를 들어 네 번째 줄의 경우 정점 3은 정점 1과 거리가 2인 간선으로 연결되어 있고, 정점 4와는 거리가 3인 간선으로 연결되어 있는 것을 보여준다. 각 줄의 마지막에는 -1이 입력으로 주어진다. 주어지는 거리는 모두 10,000 이하의 자연수이다.

출력

첫째 줄에 트리의 지름을 출력한다.

예제 입력 1 복사

5
1 3 2 -1
2 4 4 -1
3 1 2 4 3 -1
4 2 4 3 3 5 6 -1
5 4 6 -1

예제 출력 1 복사

11

 

풀이

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

// BFS 버전
public class Main {
    static int N; // 정점 개수
    static boolean[] visited; // 방문여부
    static ArrayList<int[]>[] A;
    static int farestNode; // 가장 먼 거리에 있는 노드번호
    static int maxDistance; // 가장 먼 거리
    static Queue<Integer> queue = new LinkedList<>();

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        N = Integer.parseInt(br.readLine()); // 트리 정점의 개수
        A = new ArrayList[N+1];
        visited = new boolean[N+1];

        // 인접노드 리스트 만들어주기
        for(int i=1; i<N+1; i++){
            A[i] = new ArrayList<>();
        }

        // 연결된 인접노드 리스트 값 넣어주기
        for(int i=1; i<N+1; i++){
            StringTokenizer st = new StringTokenizer(br.readLine());
            int node = Integer.parseInt(st.nextToken()); // 1번째 토큰 : 현재노드

            while (st.hasMoreTokens()){
                int nextNode = Integer.parseInt(st.nextToken());

                // -1 만나자마자 while 루프 종료
                if (nextNode == -1) break;

                int distance = Integer.parseInt(st.nextToken());
                A[node].add(new int[] {nextNode, distance});
            }
        }

        // 가장 먼 노드 찾기
        BFS(1,0); // 1번 노드에서 시작
        visited = new boolean[N+1]; // 방문배열 초기화
        maxDistance = 0; // 최대 거리 초기화
        BFS(farestNode, 0);
        System.out.println(maxDistance);

    }
    static void BFS(int node, int distance){
        visited[node] = true; // 방문체크

        // 거리 비교 후 새로운 거리값이 더 크다면 farestNode, maxDistance 업데이트
        if(distance > maxDistance){
            maxDistance = distance;
            farestNode = node;
        }
        queue.add(node);

        while (!queue.isEmpty()){
            int nextNode = queue.poll();

            // 인접노드 리스트 순회
            for(int[] next : A[nextNode]){
                int nodeNum = next[0];
                int nodeDistance = next[1];

                if(!visited[nodeNum]){
                    BFS(nodeNum, distance + nodeDistance);
                }
            }

            // for문 다 돌때까지 더 이상 탐색할 다음 노드가 없다면 백트래킹
            visited[node] = false;
        }

    }
}

 

트리 지름

  • 트리의 지름은 임의의 두 노드 사이가 가장 긴 경로이다.
  • 트리 내의 가장 먼 두 노드가 어떤 노드들인지 알지 못한다는 것이다.
  • 그래서 단순히 N번 노드가 가진 인접 노드 중에서 가장 긴 거리를 더하는 것으로는 트리의 지름을 정확히 구할 수 없다.

두 번의 BFS 가 필요하다

  • 트리에서는 어떤 두 노드가 가장 멀리 떨어져 있을지 예측할 수 없다.
  • 그래서 임의의 노드에서 가장 먼 노드를 찾고, 그 노드에서 다시 가장 먼 노드를 찾는 방식이 필요하다.
  • 트리에서 가장 먼 두 노드는 일반적으로 서로 다른 부분에 위치하므로, 어디서 시작하느냐에 따라 가장 먼 노드가 다를 수 있다.
  • 첫 번째 BFS에서 임의의 노드(1번) 에서 가장 먼 노드를 찾는다.
  • 두 번째 BFS 에서 첫번 째 BFS에서 찾은 가장 먼 노드에서 다시 가장 먼 노드를 찾고, 그 거리가 트리의 지름이 된다.