0. 개요
DFS 및 LCS 문제입니다.
이 문제는 DFS 특징을 활용한 LCS 재활용입니다.
1. DFS 특징을 활용한 LCS 재활용
문제의 예시 트리는 아래와 같습니다.
DFS를 통한 좌측 두 개의 리프 노드 탐색 순서는 아래와 같습니다.
7번 : 1 -> 2 -> 4 -> 7
8번 : 1 -> 2 -> 5 -> 8
각 경로마다 문자가 주어지니 7, 8번 리프 노드까지 도달했을 때 문자는 아래와 같습니다.
7번 : ACF
8번 : AZQ
감이 오시나요?
리프 노드까지 탐색 경로에는 중첩된 부분이 있을 수 있습니다.
또, 중첩된 경로 만큼 중복되는 문자가 있습니다.
7번과 8번의 노드는 2번 까지의 중첩되는 경로가 존재하고,
A 문자가 공통적으로 존재합니다.
그렇다면,DFS 레벨에 맞게 해당 계층의 LCS만 구하면 되지 않을까요?
LCS를 구하는 코드는 아래와 같습니다.
// 행 : level, 열 : col
boolean isMatch = (s1.charAt(depth) == s2.charAt(col)); // 문자 일치 여부 확인
int tmp = dp[depth-1][col-1] + (isMatch ? 1 : 0); // 일치하면 1 증가
dp[depth][col] = max(tmp, max(dp[depth][col-1], dp[depth-1][col])); // 갱신
탐색 깊이를 depth라고 했을 때,
각 depth 마다 dp의 정보를 갱신하고,
리프 노드에 도달하게 된다면 정답을 구하면됩니다.
주의해야할 점은,
문제 조건에 의해 루트 노드는 항상 1번입니다.
이 조건을 못봐서 계속 삽질만 했습니다....
[구현 코드]
import java.io.*;
import java.util.*;
public class Main {
private static final int MAX = 5002;
private static final int[][] lcs = new int[MAX][MAX];
private static int n, m, answer;
private static String origin;
private static List<Point>[] graph;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stz = new StringTokenizer(br.readLine());
n = Integer.parseInt(stz.nextToken());
m = Integer.parseInt(stz.nextToken());
origin = br.readLine();
graph = new List[n];
for(int i=0; i<n; i++){
graph[i] = new ArrayList<>();
}
for(int i=0; i<n-1; i++){
stz = new StringTokenizer(br.readLine());
int a = Integer.parseInt(stz.nextToken()) - 1;
int b = Integer.parseInt(stz.nextToken()) - 1;
char c = stz.nextToken().charAt(0);
graph[a].add(new Point(b, c));
graph[b].add(new Point(a, c));
}
boolean[] visited = new boolean[n];
visited[0] = true;
dfs(0, 0, visited);
System.out.println(answer);
br.close();
}
private static void dfs(int node, int depth, boolean[] visited) {
boolean isLeaf = true;
// 노드에 연결된 간선만큼 반복
for(int i=0; i<graph[node].size(); i++){
Point next = graph[node].get(i);
char c1 = next.c;
if(visited[next.to]) continue;
isLeaf = false;
// lcs
// depth에 해당하는 dp 갱신
for(int col=0; col<origin.length(); col++){
char c2 = origin.charAt(col);
lcs[depth+1][col+1] = Math.max(lcs[depth][col] + ((c1 == c2) ? 1 : 0), Math.max(lcs[depth+1][col], lcs[depth][col+1]));
}
visited[next.to] = true;
dfs(next.to, depth+1, visited);
}
if(isLeaf){
for(int j=0; j<origin.length(); j++){
answer = Math.max(answer, lcs[depth][j+1]);
}
}
}
private static class Point{
int to;
char c;
public Point(int to, char c) {
this.to = to;
this.c = c;
}
}
}
'알고리즘' 카테고리의 다른 글
프로그래머스 - 퍼즐 게임 챌린지 (0) | 2024.09.11 |
---|---|
소프티어 - 나무 섭지 (Java) (0) | 2024.06.22 |
코드 트리 - 마법의 숲 탐색(Java) (0) | 2024.06.09 |
백준 - 3197 백조의 호수(Java) (0) | 2023.09.30 |
프로그래머스 - 상담원 인원 (Java) (4) | 2023.08.08 |