[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