[SWEA 1248 : JAVA] 공통조상
1. 문제
2. 풀이
이 문제는 두 가지를 요구합니다.
- 이진트리를 구성할 수 있는가?
- 임의의 두 정점에 대해 최소 공통조상을 구할 수 있는가?
아시다시피 이진트리의 부모노드 인덱스가 N일 때, 왼쪽 자식 인덱스는 2*N이고 오른쪽 자식 인덱스는 2*N+1입니다.
이 특성을 이용해 배열로 이진트리를 많이 구성을 하는데, 이 문제는 입력으로 들어오는 간선의 순서가 무작위인데다가 부모 정점이 자식 정점보다 항상 번호가 작은 것은 아니라는 조건까지 걸려 있습니다. (입력이 이렇게 들어오는게 조금 더 현실적인 거 같긴 합니다.. 😅 )
따라서, 연결 리스트 형태로 작성해야 합니다.
저는 아래와 같이 부모, 자식 번호를 담을 변수를 둔 Node라는 클래스를 두었습니다.
class Node { int parentIdx, leftChildIdx, rightChildIdx; }
그리고 입력으로 들어오는 정보들에 대해 다음과 같이 세팅을 해주었습니다.
for (int i = 0; i < E; i++) { int parent = Integer.parseInt(st.nextToken()); int child = Integer.parseInt(st.nextToken()); if (nodes[parent].leftChildIdx == 0) nodes[parent].leftChildIdx = child; else nodes[parent].rightChildIdx = child nodes[child].parentIdx = parent; }
두 번째로 공통 조상을 구하는 부분입니다.
문제에서 root 번호는 무조건 1이라고 명시해주었기 때문에 저희는 이를 토대로 선택된 두 정점에 대해 부모노드를 구해낼 수 있습니다.
// a 정점의 부모노드를 구해내는 코드입니다. while (a != 1) { a = nodes[a].parentIdx; }
root 노드를 만날 때까지 부모노드를 계속 거슬러 올라가는 코드입니다.
이 코드를 응용하면 a와 b 정점간의 공통 조상을 찾을 수 있습니다.
위 코드로 a정점에 대해 root 노드까지 부모노드를 계속 거슬러 올라가면서 마킹을 해주는 겁니다. (visited 변수를 두는 등)
그리고 b정점에 대해 마찬가지로 부모노드를 계속 찾아가는데 이때, 마킹이 된 노드가 있다면 그것은 a정점의 부모노드였다는 의미이므로 둘 의 최소 공통 조상노드가 됩니다.
3. 코드
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.StringTokenizer; public class Solution { private static BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); private static int T; private static int V, E, a, b; private static int size; private static Node[] nodes; private static boolean[] visited; private static StringBuilder sb = new StringBuilder(); public static void main(String[] args) throws IOException { T = Integer.parseInt(in.readLine()); for (int tc = 1; tc <= T; tc++) { StringTokenizer st = new StringTokenizer(in.readLine()); V = Integer.parseInt(st.nextToken()); E = Integer.parseInt(st.nextToken()); a = Integer.parseInt(st.nextToken()); b = Integer.parseInt(st.nextToken()); nodes = new Node[V + 1]; visited = new boolean[V + 1]; for (int i = 1; i <= V; i++) { nodes[i] = new Node(i); } // 트리 생성 st = new StringTokenizer(in.readLine()); for (int i = 0; i < E; i++) { int parent = Integer.parseInt(st.nextToken()); int child = Integer.parseInt(st.nextToken()); if (nodes[parent].leftChildIdx == 0) nodes[parent].leftChildIdx = child; else nodes[parent].rightChildIdx = child; nodes[child].parentIdx = parent; } // 공통 조상 찾기 // 공통 조상을 찾고자 하는 두 노드에 대해 각각 부모 노드를 찾아가며 마킹한다. // 이때 하나의 노드가 이미 마킹된 부모노드를 만났다면 그게 공통 조상인 것. int commonParent = 1; while (true) { if (a != 1) { int parent = nodes[a].parentIdx; if (visited[parent]) { commonParent = parent; break; } visited[parent] = true; a = parent; } if (b != 1) { int parent = nodes[b].parentIdx; if (visited[parent]) { // 부모노드가 이미 마킹되어 있다면 이게 최소 공통 조상노드이다. commonParent = parent; break; } visited[parent] = true; b = parent; } } size = 0; get(nodes[commonParent]); sb.append("#").append(tc).append(" ").append(commonParent).append(" ").append(size).append("\n"); } System.out.println(sb); } static void get(Node node) { size++; if (node.leftChildIdx != 0) get(nodes[node.leftChildIdx]); if (node.rightChildIdx != 0) get(nodes[node.rightChildIdx]); } private static class Node { int data; int parentIdx, leftChildIdx, rightChildIdx; Node(int data) { this.data = data; this.parentIdx = 0; this.leftChildIdx = 0; this.rightChildIdx = 0; } } }
'Algorithm > SWEA' 카테고리의 다른 글
[SWEA 1242 : JAVA] 암호코드 스캔 (0) | 2021.08.07 |
---|---|
[SWEA 1232 : JAVA] 사칙연산 / 이진 트리 (0) | 2021.08.01 |
[SWEA 1231 : JAVA] 중위순회 / 완전 이진 트리 (0) | 2021.07.30 |
댓글
이 글 공유하기
다른 글
-
[SWEA 1242 : JAVA] 암호코드 스캔
[SWEA 1242 : JAVA] 암호코드 스캔
2021.08.07 -
[SWEA 1232 : JAVA] 사칙연산 / 이진 트리
[SWEA 1232 : JAVA] 사칙연산 / 이진 트리
2021.08.01 -
[SWEA 1231 : JAVA] 중위순회 / 완전 이진 트리
[SWEA 1231 : JAVA] 중위순회 / 완전 이진 트리
2021.07.30
댓글을 사용할 수 없습니다.