문제 링크 : https://www.acmicpc.net/problem/1167
문제를 풀기 전, 트리의 정의를 먼저 보고 가겠습니다.
https://velog.io/@kjh107704/%ED%8A%B8%EB%A6%AC-%ED%8A%B8%EB%A6%AC%EC%9D%98-%EA%B8%B0%EC%B4%88
[ 트리 ] 트리의 기초
트리.. 그래프에 이어 많이 들어보고 많이 안다고 생각하는 친구이나, 사실상 아무것도 아는 게 없었던 친구. 오늘 이후로 트리 까먹지 말자
velog.io
간단하게 요약하면, 사이클이 없는 그래프입니다.
풀이
문제에서 구하라는 트리의 지름이 무엇인지에 대해 먼저 보고 가겠습니다.

트리 1에서 서로 가장 먼 두 노드 간의 거리를 트리의 지름이라고 문제에서 말해주고 있습니다. 만일 모든 간선의 가중치가 1인 경우 가장 먼 노드의 집합은 8과 9이며 그 값은 6입니다.

근데 만약 1번 노드와 4번 노드의 가중치가 100이라면 가장 먼 노드의 집합은 8,4 혹은 9,4가 됩니다.

그럼 이 트리 3에서는 어떨까요. 트리의 지름을 가지는 노드의 집합은 9,7이 됩니다.
즉 모든 노드에서 탐색을 수행한다면 N^3의 시간복잡도가 나오기 때문에 다른 방법을 생각해야 합니다.

트리를 단순화시켜봤습니다. 위 트리에서 트리의 지름을 구하는 케이스를 생각해 봅시다.
우선 트리 1,2와 같이 "sub1의 최대 지름 + sub2의 최대지름 + R에서 sub1의 비용 + R에서 sub2의 비용"이 트리의 지름이 될 수 있습니다.
그럼 트리 3과 같이 R을 지나지 않고 트리의 지름을 이루는 경우는 아래의 트리를 통해 나타낼 수 있습니다.

만일 sub3의 지름 + sub4의 지름이 "sub1의 최대 지름 + sub2의 최대지름 + R에서 sub1의 비용 + R에서 sub2의 비용" 보다 크다면 트리의 지름을 구하는 경로에 R이 포함되지 않습니다.
위 2가지 상황을 정리해 볼 수 있습니다.
1. 트리의 지름은 루트의 서브트리 중 제일 값이 큰 N(>=1) 개의 지름의 합
2. 트리의 지름은 모든 서브트리 중 제일 값이 큰 2개의 지름의 합
이 2가지의 상황에서 항상 포함되는 노드는 루트노드에서 가장 먼 노드라는 것을 생각해 낼 수 있습니다.
즉 루트 노드에서 탐색하여 구한 가장 먼 노드 N1은 트리의 지름을 구하는데 무조건 들리게 되니 N1에서 탐색을 통해 가장 먼 노드와의 거리를 구해주면 됩니다.
+
N1에서 가장 먼 노드의 거리를 구하는 과정에서 DP를 도입해 봤는데, 특정 점을 중복하여 방문하는 경우가 없어서 쓸모가 없습니다ㅠ.
시간도 더 오래 걸리더라고요.

코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Num1167트리의지름 {
private static class Edge{
int end;
int cost;
Edge(int end,int cost){
this.end = end;
this.cost = cost;
}
}
static int n,depthNode,maxCost;
static List<List<Edge>> map;
static int[] memo;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
n = Integer.parseInt(br.readLine());
map = new ArrayList<>();
memo = new int[n+1];
for(int i=0;i<=n;i++){
map.add(new ArrayList<>());
}
// Input
// can start 1
Arrays.fill(memo,-1);
for(int i=0;i<n;i++){
StringTokenizer st = new StringTokenizer(br.readLine());
int node = Integer.parseInt(st.nextToken());
while (true){
int end = Integer.parseInt(st.nextToken());
if(end == -1) break;
int cost = Integer.parseInt(st.nextToken());
map.get(node).add(new Edge(end,cost));
}
}
maxCost = 0;
depthNode = 0;
findMaxDepth(0,1,0);
// System.out.println(depthNode);
System.out.println(DFS(0,depthNode));
}
public static void findMaxDepth(int preNode,int nowNode,int totalCost){
for(Edge next : map.get(nowNode)){
if(next.end == preNode) {
if(maxCost <totalCost){
depthNode = nowNode;
maxCost = totalCost;
}
continue;
}
findMaxDepth(nowNode,next.end,totalCost+next.cost);
}
}
public static int DFS(int preNode ,int nowNode){
if(memo[nowNode] !=-1) return memo[nowNode];
memo[nowNode] = 0;
for(Edge next : map.get(nowNode)){
if(next.end == preNode) continue;
memo[nowNode] = Math.max(memo[nowNode],DFS(nowNode,next.end)+next.cost);
}
return memo[nowNode];
}
}
'머리깨지며 배우는 코테풀이 > 백준 문제집 [단기간 성장]' 카테고리의 다른 글
[JAVA] 백준 20183 골목 대장 호석 - 효율성 2 (3) | 2024.09.24 |
---|---|
[Java] 백준 1981번 배열에서 이동 (0) | 2024.07.18 |
[JAVA] 9370 미확인 도착지 (1) | 2023.10.29 |
[JAVA] 1039 교환 (0) | 2023.10.25 |
[JAVA] 10942 팰린드롬? (0) | 2023.05.26 |