PS/Java

[백준 19581] 두 번째 트리의 지름

siyamaki 2022. 7. 19. 14:33

트리에 N개의 정점이 있고, 각 정점 별로 1부터 N까지의 번호가 붙어있다.

트리에서 가장 먼 두 정점 간의 거리를 트리의 지름이라고 한다. 트리의 지름을 구하는 문제는 너무 많기 때문에 우리는 두 번째 트리의 지름을 구하려고 한다.

 

두 번째 트리의 지름은 무엇이냐? 바로 두 번째로 가장 먼 두 정점 간의 거리를 의미한다. (두 번째 트리의 지름은 트리의 지름과 같을 수 있다.)

바로 두 번째 트리의 지름을 구해보자.


입력

첫 번째 줄에는 정점의 개수 N(3 ≤ N ≤ 100,000)이 들어온다.

둘째 줄부터 N번째 줄까지 각 간선에 대한 정보가 들어온다. 간선에 대한 정보는 세 개의 정수로 이루어져 있다. 첫 번째 정수와 두 번째 정수는 간선과 연결된 정점 번호를 나타내고, 세 번째 정수는 간선의 가중치를 나타낸다. 간선의 가중치는 20,000 이하의 자연수이다.

출력

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


예제 입력

7
1 2 1
2 3 2
1 4 3
1 5 1
5 6 1
6 7 1

예제 출력

6

트리의 지름을 구하는 방법은(2022.07.19 - [PS/Java] - [백준] 1967. 트리의 지름)과 동일하다

두번째 트리의 지름을 구해야 하는데 임의의 정점으로부터 가장 먼 정점 A를 찾고

A로부터 가장 먼 정점 B를 찾아 트리의 지름을 구한다.

A로부터 B를 제외한 가장 먼 정점까지의 거리, B로부터 A를 제외한 가장 먼 정점까지의 거리를 구하고

두 값의 최대값을 구하면 두 번째 트리의 지름을 구할 수 있다. 제외하는 이유는 해당 값이 항상 첫 번째 가장 큰 트리의 지름이기 때문이다.

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class Main {
    public static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    public static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    public static int N, maxTo, maxW;
    public static int a, b, minA, minB;
    public static ArrayList<Node>[] adjList;
    public static boolean[] visited;
    public static class Node {
        int next;  // 누구랑 연결되어있는지
        int w;      // 가중치

        public Node (int next, int w) {
            this.next = next;
            this.w = w;
        }
    }
    
    public static void main(String[] args) throws Exception {
        N = Integer.parseInt(br.readLine());
        adjList = new ArrayList[N + 1];

        for(int i = 1; i <= N; i++) {
            adjList[i] = new ArrayList<>();
        }
        
        for(int i = 0; i < N - 1; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            int from = Integer.parseInt(st.nextToken());
            int to = Integer.parseInt(st.nextToken());
            int weight = Integer.parseInt(st.nextToken());

            adjList[from].add(new Node(to, weight));
            adjList[to].add(new Node(from, weight));
        }

        maxTo = 0;
        visited = new boolean[N + 1];
        maxW = Integer.MIN_VALUE;
        dfs(1, 0);  // 어디까지 제일 먼지 체크해서 값 기억
        // maxTo, maxW 구해짐 -> a
        a = maxTo;


        visited = new boolean[N + 1];
        maxW = Integer.MIN_VALUE;
        dfs(maxTo, 0);
        b = maxTo;


        visited = new boolean[N + 1];
        visited[b] = true;
        maxW = Integer.MIN_VALUE;
        dfs(a, 0);
        minA = maxW;

        visited = new boolean[N + 1];
        visited[a] = true;
        maxW = Integer.MIN_VALUE;
        dfs(b, 0);
        minB = maxW;

        bw.write(Math.max(minA, minB) + "");
        
        br.close();
        bw.flush();
        bw.close();
    }

    public static void dfs(int from, int dist) {
        if(visited[from]) {
            return;
        }
        if(maxW < dist) {
            maxTo = from;
            maxW = dist;
        }
        visited[from] = true;
        for(int i = 0; i < adjList[from].size(); i++) {
            Node nextNode = adjList[from].get(i);
            int next = nextNode.next;
            int w = nextNode.w;
            if(!visited[next]) {
                dfs(next, dist + w);
            }
        }
    }
}