문제 - https://www.acmicpc.net/problem/3176

 

3176번: 도로 네트워크

첫째 줄에 N이 주어진다. (2 ≤ N ≤ 100,000) 다음 N-1개 줄에는 도로를 나타내는 세 정수 A, B, C가 주어진다. A와 B사이에 길이가 C인 도로가 있다는 뜻이다. 도로의 길이는 1,000,000보다 작거나 같은 양

www.acmicpc.net

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

public class Main {

    static int N, M, K;
    static int[] depth;
    static int[][] dp, min, max;
    static class E{
        int target, cost;
        public E(int target, int cost){
            this.target = target;
            this.cost = cost;
        }
    }static ArrayList<E>[] V;
    static StringBuilder sb;

    public static void main(String[] args) throws Exception {
//        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("./input.txt")));
        StringTokenizer st;

        N = Integer.parseInt(br.readLine()); // N 입력
        while (Math.pow(2, K)<=N) K++; // 2^K>N 인 최소 K 구하고
        // 변수 초기화
        depth = new int[N+1];
        dp = new int[N+1][K];
        min = new int[N+1][K];
        max = new int[N+1][K];
        V = new ArrayList[N+1];
        for (int i = 1; i < N+1; i++)
            V[i] = new ArrayList<>();

        for (int i = 0; i < N-1; i++) { // 양방향 간선추가
            st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            int c = Integer.parseInt(st.nextToken());
            V[a].add(new E(b, c));
            V[b].add(new E(a, c));
        }

        dfs(1, 1); // depth 구하고
        for (int k = 1; k < K; k++) // 모든 2^k번째 부모 구하기
            for (int v = 1; v <= N; v++) {
                dp[v][k] = dp[ dp[v][k - 1] ][k - 1]; // [v]의 [2^k번째 부모]는 [v의 2^k-1번째 부모]의 [2^k-1번째 부모]
                min[v][k] = Math.min(min[v][k-1], min[ dp[v][k-1] ][ k-1 ]);
                max[v][k] = Math.max(max[v][k-1], max[ dp[v][k-1] ][ k-1 ]);
            }

        sb = new StringBuilder();
        M = Integer.parseInt(br.readLine());
        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());
            int from = Integer.parseInt(st.nextToken());
            int to = Integer.parseInt(st.nextToken());
            distance(from, to);
        }
        bw.write(sb.toString());

        bw.flush();
        bw.close();
        br.close();
    }

    static void dfs(int now, int cnt){
        depth[now] = cnt;
        for (E next : V[now])
            if(depth[next.target]==0){
                dp[next.target][0] = now;
                min[next.target][0] = next.cost;
                max[next.target][0] = next.cost;
                dfs(next.target, cnt+1);
            }
    }

    static void distance(int from, int to) {
        if (depth[from]<depth[to]){ // 무조건 from 이 더 낮은 위치에 오도록
            int tmp = from;
            from = to;
            to = tmp;
        }
        int shortest = 1000000;
        int longest = 1;
        for (int k = K-1; k >= 0; k--) { // 높이 맞춰주고
            if (Math.pow(2, k) <= depth[from]-depth[to]){
                shortest = Math.min(shortest, min[from][k]);
                longest = Math.max(longest, max[from][k]);
                from = dp[from][k];
            }
        }
        if (from==to){ // 같으면
            sb.append(shortest+" "+longest+"\n");
            return;
        }
        for (int k = K-1; k >= 0; k--) { // lca 찾을때까지
            if (dp[from][k]!=dp[to][k]){
                shortest = Math.min(shortest, Math.min(min[from][k], min[to][k]));
                longest = Math.max(longest, Math.max(max[from][k], max[to][k]));
                from = dp[from][k];
                to = dp[to][k];
            }
        }
        shortest = Math.min(shortest, Math.min(min[from][0], min[to][0]));
        longest = Math.max(longest, Math.max(max[from][0], max[to][0]));
        sb.append(shortest+" "+longest+"\n");
    }
}

 

LCA를 이용해야한다는걸 파악하는데 시간이 꽤 걸렸고, LCA를 응용해서 구현하는데도 시간이 꽤 걸렸다.

반복적으로 연습할 필요가 있어보인다.

'공부 > algorithm' 카테고리의 다른 글

BOJ 최단경로(1753) - Java  (0) 2021.08.09
BOJ 단절점(11266) - Java  (0) 2021.08.09
BOJ 교수님은 기다리지 않는다(3830) - Java  (0) 2021.08.05
BOJ 게임 개발(1516) - Java  (0) 2021.08.04
BOJ 키 순서(2458) - Java  (0) 2021.08.04

+ Recent posts