ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준] 11437, 11438 LCA (2)
    ALGORITHM/BOJ 2020. 12. 7. 22:50

    www.acmicpc.net/problem/11438

     

    11438번: LCA 2

    첫째 줄에 노드의 개수 N이 주어지고, 다음 N-1개 줄에는 트리 상에서 연결된 두 정점이 주어진다. 그 다음 줄에는 가장 가까운 공통 조상을 알고싶은 쌍의 개수 M이 주어지고, 다음 M개 줄에는 정

    www.acmicpc.net

    www.acmicpc.net/problem/11437

     

    11437번: LCA

    첫째 줄에 노드의 개수 N이 주어지고, 다음 N-1개 줄에는 트리 상에서 연결된 두 정점이 주어진다. 그 다음 줄에는 가장 가까운 공통 조상을 알고싶은 쌍의 개수 M이 주어지고, 다음 M개 줄에는 정

    www.acmicpc.net

    2020-12-07


     
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.StringTokenizer;
     
    public class Main11438 {
        public static int N, M, dp[][], depth[];
        public static List<List<Integer>> list;
        public static boolean vtd[];
        public static int maxLevel = 21;
     
        public static void dfs(int cur, int parent) {
            vtd[cur] = true//방문 노드 체크
            //현재노드의 depth는 부모노드의 depth+1 이어야한다.
            //이 때, root node의 depth를 1로 잡는다
            depth[cur] = depth[parent] + 1;  
     
            for(int next: list.get(cur)) { // 현재 node와 연결된 노드들을 찾아서 depth체크, dp 부모값에 저장한다.
                if(!vtd[next]) { //방문한적이 없는 노드인 경우에만 체크한다.
                    vtd[next] = true// 방문 체크 true 
                    dp[next][0= cur; // 다음 갈 노드의 부모노드는 현재 노드 값이다.
                    dfs(next, cur); //next값이 현재값이 되고, 현재 값이 부모값이 된다.
                }
            }
        }
     
        public static void solve() {
            for(int y = 1; y <= maxLevel; y++) { // 1 -> maxLevel
                for(int x = 1; x <= N; x++) { // 1 -> N 노드까지 체크
                    dp[x][y] = dp[dp[x][y-1]][y-1];
                }
            }
        }
     
        public static int lca(int x, int y) {
            //x를 더 깊은 depth로 가정한다.
            //그래서 만약 y의 depth가 더 깊은 경우, x, y를 swap 한다.
            if(depth[x] < depth[y]) { 
                int tmp = y;
                y = x;
                x = tmp;
            }
     
            for(int i = maxLevel; i >= 0; i--) {
                //두 노드의 depth 차이가 2^i보다 작거나 같을 때...
                //x를 y의 depth에 맞춘다 
                if(Math.pow(2, i) <= depth[x] - depth[y]) {
                    x = dp[x][i];
                }
            }
     
            if(x == y) return x; //두 노드의 부모 노드가 같다면? 그대로 return x
            else { //depth는 같으나 부모노드가 다르다면? 
                for(int i = maxLevel; i >= 0; i--) {
                    //현재 같은 depth를 갖고 있기 때문에, 둘이 같은 공통 분모를 만날 수 있도록 레벨을 체크한다.
                    if(dp[x][i] != dp[y][i]) {
                        x = dp[x][i];
                        y = dp[y][i];
                    }
                }
                x = dp[x][0]; //공통 부모 직전까지 체크했으므로, 그 노드의 부모 노드를 return한다.
            }
            return x;
        }
     
        public static void main(String[] args) throws Exception {
            BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
            StringTokenizer st = new StringTokenizer(bf.readLine().trim());
            N = Integer.parseInt(st.nextToken());
            // root 노드를 1부터 시작
            dp = new int[N+1][maxLevel+1]; // dp[x][y] 형태로 x의 2^y 부모노드를 저장
            depth = new int[N+1]; // 각 노드의 부모 노드 저장 배열
            vtd = new boolean[N+1]; // dfs 돌 때 방문 체크 배열
            list = new ArrayList<>();
     
            for(int i = 0; i <= N; i++) list.add(new ArrayList<>()); //초기화
     
            for(int i = 0; i < N-1; i++) { // 입력
                st = new StringTokenizer(bf.readLine());
                int x = Integer.parseInt(st.nextToken());
                int y = Integer.parseInt(st.nextToken());
                list.get(x).add(y);
                list.get(y).add(x);
            } 
     
            dfs(10); // dfs로 노드들을 순회하면서, 각각의 depth를 찾고, 부모노드들을 저장한다.
            solve(); // dp를 활용하여, 각 노드의 2^i 부모노드들을 저장한다.
     
            st = new StringTokenizer(bf.readLine().trim());
            M = Integer.parseInt(st.nextToken());
     
            for(int i = 0; i < M; i++) {
                st = new StringTokenizer(bf.readLine());
                int x = Integer.parseInt(st.nextToken());
                int y = Integer.parseInt(st.nextToken());
                System.out.println(lca(x, y));
            }
        }
    }
    cs

    여러 블로그들을 통해 LCA 개념에 대해서 공부한 후 풀었다. 

    자세한 것은 주석을 확인하면 된다.

    'ALGORITHM > BOJ' 카테고리의 다른 글

    [백준] 1175 배달  (2) 2020.12.20
    [백준] 16234 인구이동  (0) 2020.12.16
    [백준] 1946 신입사원  (0) 2020.12.06
    [백준] 9372 상근이의 여행  (0) 2020.12.05
    [백준] 9466 텀 프로젝트  (0) 2020.12.01

    댓글

Programming Diary