알고리즘/백준

1167_트리의 지름

베리영young 2024. 12. 23. 01:49

사용 알고리즘: bfs

사용 언어: java

 

package week29;

import java.io.*;
import java.util.*;
public class Main_bj_1167_트리의지름 {
	static int v;
	static List<int[]>[] list;

	public static void main(String[] args) throws NumberFormatException, IOException {
		init_트리의지름();
		
		int[] end = find(1);
		int[] answer = find(end[0]);
		
		System.out.println(answer[1]);
	}

	private static int[] find(int startNode) {
		boolean[] visit = new boolean[v+1];
		visit[startNode] = true;
		int endNode = -1;
		int maxLen = 0;
		Queue<int[]> q = new ArrayDeque<>();
		q.add(new int[] {startNode, 0});
		
		while(!q.isEmpty()) {
			int[] p = q.poll();
			
			if(maxLen < p[1]) {
				maxLen = p[1];
				endNode = p[0];
			}
			
			for(int[] nxt : list[p[0]]) {
				if(!visit[nxt[0]]) {
					visit[nxt[0]]  = true;
					q.add(new int[] {nxt[0], p[1]+nxt[1]});
				}
			}
		}
		return new int[] {endNode, maxLen};
	}

	private static void init_트리의지름() throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		v = Integer.parseInt(br.readLine());
		list = new ArrayList[v+1];
		for(int i=0; i<v+1; i++) {
			list[i] = new ArrayList<>();
		}
		
		StringTokenizer st;
		for(int i=1; i<v+1; i++) {
			st = new StringTokenizer(br.readLine());
			int node = Integer.parseInt(st.nextToken());
			
			while(true) {
				int nxtNode = Integer.parseInt(st.nextToken());
				if(nxtNode == -1) break;
				int cost = Integer.parseInt(st.nextToken());
				
				list[node].add(new int[] {nxtNode, cost});
			}
		}
	}

}

 

프로그래머스에서도 이런 비슷한 문제를 풀었던 거 같다.

 

임의의 점 A에서 가장 먼 점이 C일 때,

C에서 가장 먼 점 B(A와 B가 같을 수도 있음)를 찾아갈 때, A~C의 경로와 B~C의 경로는 일부 겹치게 된다.

 

그렇기 때문에, 임의의 점(나는 1번 노드로 정함)에서 가장 먼 곳에 있는 점을 구한 후(endNode),

그 점을 다시 시작점으로 놓고 가장 먼 곳의 거리(maxLen)을 구했다.

 

이때 각각을 따로 구하기 위해 bfs를 두 번 구현하는 건 비효율적이라고 생각했다.

어차피 두 번의 bfs 모두 가장 먼 곳의 점과 거리를 알고 있어야 하기 때문이다.

 

그래서 int[]로 리턴 받는 bfs를 만들어서, 각 경우에 필요한 것만 사용하였다.