[백준 1761] 정점들의 거리(Java)

최민길(Gale)·2024년 1월 21일
1

알고리즘

목록 보기
167/172

문제 링크 : https://www.acmicpc.net/problem/1761

이 문제는 LCA 알고리즘을 이용하여 풀 수 있습니다. 우선 두 노드 쌍을 입력받을 때 두 노드 사이의 거리를 출력하는 방법에 대해 생각해보아야 합니다.

두 노드 사이의 거리는 다음과 같습니다.

루트 노드에서 A 노드까지의 거리 + 루트 노드에서 B 노드까지의 거리 - 2 X (루트 노드에서 공통 조상 노드까지의 거리)

따라서 루트 노드에서 모든 정점까지의 거리 정보를 저장한 후 LCA를 구해 위 거리 공식에 대입하면 됩니다.

여기서 주의할 점은 LCA 알고리즘 내부에서 거리 계산을 진행할 경우 틀릴 수 있다는 점입니다. (실제 제출 시 틀렸다고 나타났습니다.) 따라서 되도록이면 LCA 알고리즘을 그대로 유지한 채 외부에서 이 값을 이용한 방법으로 계산하는 것이 안전하다고 볼 수 있겠습니다.

다음은 코드입니다.

import java.util.*;
import java.io.*;

class Main{
    static List<List<Node>> graph = new ArrayList<>();
    static int[][] parent;
    static int[] depth;
    static boolean[] check;
    static int[] distance;
    static int K;

    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());
        for(int i=0;i<=N;i++) graph.add(new ArrayList<>());

        for(int i=1;i<N;i++){
            StringTokenizer st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            int d = Integer.parseInt(st.nextToken());
            graph.get(a).add(new Node(a,b,d));
            graph.get(b).add(new Node(b,a,d));
        }

        int root = 0;
        for(int i=1;i<=N;i++){
            check = new boolean[N+1];
            checkGraph(i);
            int cnt = 0;
            for(boolean isCheck : check) if(isCheck) cnt++;
            if(cnt == N){
                root = i;
                break;
            }
        }

        K = getK(N);
        check = new boolean[N+1];
        depth = new int[N+1];
        parent = new int[K+1][N+1];
        distance = new int[N+1];
        setDepth(root,0,0);

        for(int k=1;k<=K;k++){
            for(int n=1;n<=N;n++){
                parent[k][n] = parent[k-1][parent[k-1][n]];
            }
        }

        StringBuilder sb = new StringBuilder();
        int M = Integer.parseInt(br.readLine());
        for(int i=0;i<M;i++){
            StringTokenizer st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            int lca = depth[a]>depth[b] ? lca(b,a) : lca(a,b);
            sb.append(distance[a] + distance[b] - 2*distance[lca]).append("\n");
        }
        System.out.println(sb);
    }

    private static int lca(int a, int b){
        for(int k=K;k>=0;k--){
            if(Math.pow(2,k) <= depth[b] - depth[a]){
                if(depth[a] <= depth[parent[k][b]]) b = parent[k][b];
            }
        }

        for(int k=K;k>=0;k--){
            if(parent[k][a] != parent[k][b]){
                a = parent[k][a];
                b = parent[k][b];
            }
        }

        return a!=b ? parent[0][a] : a;
    }

    private static void setDepth(int start, int cnt, int d){
        check[start] = true;
        depth[start] = cnt;
        distance[start] = d;

        List<Node> nextList = graph.get(start);
        for(Node next : nextList){
            if(!check[next.end]){
                parent[0][next.end] = start;
                setDepth(next.end, cnt+1, d+next.distance);
            }
        }
    }

    private static int getK(int N){
        int H = 0;
        int L = N;
        while(L>1){
            H++;
            L/=2;
        }
        return H;
    }

    private static void checkGraph(int start){
        check[start] = true;

        List<Node> nextList = graph.get(start);
        for(Node next : nextList){
            if(!check[next.end]) checkGraph(next.end);
        }
    }

    static class Node{
        int start;
        int end;
        int distance;

        Node(int start, int end, int distance){
            this.start = start;
            this.end = end;
            this.distance = distance;
        }
    }
}

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글

관련 채용 정보