한동안 티스토리 서버가 날아간 덕분에 문제 풀고 풀이를 못 올렸는데
정말 문제 푼 것 같지가 않았다.. ㅎ
오늘의 문제는 트리의 지름이다.
문제를 읽자마자 작성한 나의 주석을 먼저 보자.
1
2
3
4
5
6
7
8
9
10
11
12
|
// 트리의 지름 ?
// 루트에서 가장 먼 노드 n1 <-> n1과 가장 멀리 있는 노드 n2의 거리.
// 가중치와 에지 정보가 모두 필요하므로 별도의 Node 클래스가 필요하다.
// bfs dfs? dfs를 이상하게 구현하지 않는 이상 큰 의미 없을 듯..? 어차피 완전탐색해야함.
// 다만 깊이가 깊어질수록 dfs가 불리해서 굳이 선택하면 bfs가 무난한데 난 dfs가 좋 - 아
// 가장 먼 노드 + 그놈하고 제일 먼 노드 => 두 번 탐색 필요
// 근데 노드가 1번부터 시작하는 건지 0번부터인지 기재되어 있지 않음.. 뭐지
// 예제는 1번부터니 일단 1번으로 시작
// 1번째 입력값 노드 개수 V
// 2번째 입력값 노드 번호 N, 에지 정보 V, -1이 나오면 다음 노드로
|
cs |
문제 자체가 어렵진 않았는데 생각보다 고민할 게 많았다.
어떤 변수가 필요한지 등등..
1. 일단 트리의 지름은 (루트에서 가장 먼 노드)로부터 가장 멀리 있는 노드이다.
몰랐으면 지금부터 알면 된다. 나도 전에 다른 문제 풀면서 알았다.
2. 가중치가 들어가는 문제의 경우 클래스를 만들어서 푸는 게 일반적이다. 물론 다른 방법도 있다.
3. 완전 탐색으로 가장 깊은 노드를 찾아야 하는데, 아무래도 dfs는 깊이가 깊어질수록 불리하므로 bfs가 무난하긴 하다.
근데 난 dfs가 좋으므로 비합리적인 선택을 할 것이다. 틀리면 다시 풀면 되지.
4. 노드가 몇 번부터 시작하는지 모르겠는데 예제에서는 1번부터 시작함. 일단 그걸 기준으로 배열을 만들기로 했다.
이런 전제 조건을 바탕으로 야매 수도코드를 작성해봤다.
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
|
public class Main {
// 가장 멀리 있는 노드 기록할 변수 생성 -> 초기화 필요 없음
public static int max_node;
// max 가중치 기록할 변수 생성 -> 초기화 필요 없음
public static int max_weight;
public static final int START_NODE = 1;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 트리의 지름 ?
// 루트에서 가장 먼 노드 n1 <-> n1과 가장 멀리 있는 노드 n2의 거리.
// 가중치와 에지 정보가 모두 필요하므로 별도의 Node 클래스가 필요하다.
// bfs dfs? dfs를 이상하게 구현하지 않는 이상 큰 의미 없을 듯..? 어차피 완전탐색해야함.
// 다만 깊이가 깊어질수록 dfs가 불리해서 굳이 선택하면 bfs가 무난한데 난 dfs가 좋 - 아
// 가장 먼 노드 + 그놈하고 제일 먼 노드 => 두 번 탐색 필요
// 근데 노드가 1번부터 시작하는 건지 0번부터인지 기재되어 있지 않음.. 뭐지
// 예제는 1번부터니 일단 1번으로 시작
// 1번째 입력값 노드 개수 V
// 2번째 입력값 노드 번호 N, 에지 정보 V, -1이 나오면 다음 노드로
// 노드 개수 V 받기
// 노드개수 V+1 만큼의 ArrayList<Node>를 인자로 가지는 배열 lists 생성
// 2중 반복문
// 1차 (lists.length만큼)
// lists[i] = new ArrayList<Node>;
// 2번째 입력값 받아서 split or StringTokenizer
// 2차 for(2번째 입력값 배열 길이만큼, +2씩 증가)
// 0번은 노드 번호이므로 1번부터
// 첫번째 입력값이 -1? break
// 아니라면 lists[j]
// lists[j+1] = .. 퐁당퐁당 넣기
// lists[i].add (new Node (j , j+1));
// 방문 여부 기록용 변수 생성(+1)
// 가중치용 변수 (무의미함)
// dfs(현재 노드, 배열, 방문용 배열, 가중치)
// 방문 여부 초기화
// dfs(max node, 배열, 방문용 배열, 가중치)
// 출력 최대 가중치
}
// dfs(현재 노드, 방문용 배열, 배열, 가중치)
// 방문했다면 리턴
// 만약 최대 가중치보다 지금 가중치가 더 크다면?
// 최대 가중치 = 현재 가중치
// 최대 가중치 노드 = 현재 노드
// 반복문
// 배열[노드]의 길이만큼 돌면
// if (방문 안함)
// dfs(현재 노드, 방문용 배열, 배열, 가중치 + 다음 노드의 가중치)
}
}
// 노드 클래스
class Node {
// 가중치
int weight;
// 에지 정보
int edge;
// 생성자
public Node (int weight, int edge) {
this.weight = weight;
this.edge = edge;
}
}
|
cs |
사실 가중치나 가중치를 가진 노드를 저장하는 것도 정적 변수가 아니라 배열을 만들어서 해도 되지만
작성하다보니 인자가 너무 많아지는 것 같아서 실수할 확률을 줄이기 위해서 밖으로 빼버렸다
만약 코테가 면접까지 이어진다면 생각하면 최대한 정적 변수는 배제하는 게 좋을 것 같긴 하다
근데 틀리면 의미 없으니 실수 많이 하는 사람은 정적 변수라도 쓰자
max_node나 max_weigth같은 경우는 무조건 두 번째가 더 빠르기 때문에 굳이 초기화해줄 필요 없음.
그리고 위에서 말했던 것처럼 dfs는 두 번 반복할 것이다.
그리고 늘 그렇듯 틀렸다
근데 거의 정답에 근접한 상태라서 더이상 설명하면 그냥 정답이 나오니까 직접 풀어보자
힌트 = 문제에서 제시해주는 값 중 하나가 별 의미 없어보인다? -> 무조건 뭔가 잘못 생각하고 있는 것
늘 알면서도 같은 실수를 반복하지..
정답은 아래에
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
101
102
103
104
105
106
107
108
109
110
111
112
|
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
public class Main {
// 가장 멀리 있는 노드 기록할 변수 생성 -> 초기화 필요 없음
public static int max_node;
// max 가중치 기록할 변수 생성 -> 초기화 필요 없음
public static int max_weight;
public static final int START_NODE = 1;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 트리의 지름 ?
// 루트에서 가장 먼 노드 n1 <-> n1과 가장 멀리 있는 노드 n2의 거리.
// 가중치와 에지 정보가 모두 필요하므로 별도의 Node 클래스가 필요하다.
// bfs dfs? dfs를 이상하게 구현하지 않는 이상 큰 의미 없을 듯..? 어차피 완전탐색해야함.
// 다만 깊이가 깊어질수록 dfs가 불리해서 굳이 선택하면 bfs가 무난한데 난 dfs가 좋 - 아
// 가장 먼 노드 + 그놈하고 제일 먼 노드 => 두 번 탐색 필요
// 근데 노드가 1번부터 시작하는 건지 0번부터인지 기재되어 있지 않음.. 뭐지
// 예제는 1번부터니 일단 1번으로 시작
// 1번째 입력값 노드 개수 V
// 2번째 입력값 노드 번호 N, 에지 정보 V, -1이 나오면 다음 노드로
// 노드 개수 V 받기
int V = Integer.parseInt(br.readLine());
// 노드개수 V+1 만큼의 ArrayList<Node>를 인자로 가지는 배열 lists 생성
ArrayList<Node>[] lists = new ArrayList[V+1];
// 2중 반복문
for (int i=START_NODE; i<lists.length; i++) {
// 1차 (lists.length만큼)
// lists[i] = new ArrayList<Node>;
String[] input = br.readLine().split(" ");
// 2번째 입력값 받아서 split or StringTokenizer
int node = Integer.parseInt(input[0]);
lists[node] = new ArrayList<>();
for (int j=1; j< input.length; j+=2) {
// 2차 for(2번째 입력값 배열 길이만큼, +2씩 증가)
// 0번은 노드 번호이므로 1번부터
int input1 = Integer.parseInt(input[j]); // 노드
// 첫번째 입력값이 -1? break
if (input1 == -1) break;
// 아니라면 lists[j]
int input2 = Integer.parseInt(input[j+1]); // 가중치
// lists[j+1] = .. 퐁당퐁당 넣기
// lists[i].add (new Node (j , j+1));
lists[node].add(new Node(input2,input1));
}
}
// 방문 여부 기록용 변수 생성(+1)
boolean[] visited = new boolean[V+1];
// 가중치용 변수 (무의미함)
int weight = 0;
// dfs(현재 노드, 배열, 방문용 배열, 가중치)
dfs(START_NODE, visited,lists, weight);
// 방문 여부 초기화
visited = new boolean[V+1];
// dfs(max node, 배열, 방문용 배열, 가중치)
dfs(max_node, visited, lists, weight);
// 출력 최대 가중치
System.out.println(max_weight);
}
// dfs(현재 노드, 방문용 배열, 배열, 가중치)
public static void dfs(int node, boolean[] visited, ArrayList<Node>[] lists, int weight) {
// 방문했다면 리턴
if (visited[node]) return;
// 만약 최대 가중치보다 지금 가중치가 더 크다면?
// 최대 가중치 = 현재 가중치
// 최대 가중치 노드 = 현재 노드
if (max_weight < weight) {
max_weight = weight;
max_node = node;
}
visited[node] = true;
// 반복문
// 배열[노드]의 길이만큼 돌면서
for (int i=0; i<lists[node].size(); i++) {
// if (방문 안함)
Node next = lists[node].get(i);
if (!visited[next.edge]) {
// dfs(현재 노드, 방문용 배열, 배열, 가중치 + 다음 노드의 가중치)
dfs(next.edge, visited, lists, weight + next.weight);
}
}
}
}
// 노드 클래스
class Node {
// 가중치
int weight;
// 에지 정보
int edge;
// 생성자
public Node (int weight, int edge) {
this.weight = weight;
this.edge = edge;
}
}
|
cs |
주석은 처음 작성하고 수정하지 않으니 신경쓰지 말자
'CS ﹒ Algorithm > Baekjoon' 카테고리의 다른 글
Java 백준 문제풀이 (57) 1300 _ K번째 수 (0) | 2022.10.27 |
---|---|
Java 백준 문제풀이 (56) 2343_ 기타 레슨 (0) | 2022.10.25 |
Java 백준 문제풀이 (54) 미로 탐색 (0) | 2022.10.15 |
Java 백준 문제풀이 (53) 13023 _ ABCDE (0) | 2022.10.13 |
Java 백준 문제풀이 (52) 2023_신기한 소수 (2) | 2022.10.12 |