분류: 트리, DFS /
문제
문제 설명
트리의 지름이란, 트리에서 임의의 두 점 사이의 거리 중 가장 긴 것을 말한다. 트리의 지름을 구하는 프로그램을 작성하시오.
입력
트리가 입력으로 주어진다. 먼저 첫 번째 줄에서는 트리의 정점의 개수 V가 주어지고 (2 ≤ V ≤ 100,000)둘째 줄부터 V개의 줄에 걸쳐 간선의 정보가 다음과 같이 주어진다. 정점 번호는 1부터 V까지 매겨져 있다.
먼저 정점 번호가 주어지고, 이어서 연결된 간선의 정보를 의미하는 정수가 두 개씩 주어지는데, 하나는 정점번호, 다른 하나는 그 정점까지의 거리이다. 예를 들어 네 번째 줄의 경우 정점 3은 정점 1과 거리가 2인 간선으로 연결되어 있고, 정점 4와는 거리가 3인 간선으로 연결되어 있는 것을 보여준다. 각 줄의 마지막에는 -1이 입력으로 주어진다. 주어지는 거리는 모두 10,000 이하의 자연수이다.
출력
첫째 줄에 트리의 지름을 출력한다.
풀이
- 내 풀이
#include <iostream>
#include <vector>
using namespace std;
struct link {int x, w;};
int V, farV, maxDist;
bool isLeaf;
bool vis[100001];
vector<link> adj[100001];
void dfs(int cur, int dist) {
vis[cur] = true;
isLeaf = true;
for(auto [x, w]: adj[cur]) {
if(vis[x]) continue;
if(isLeaf) isLeaf = false;
dfs(x, dist + w);
}
if(isLeaf && dist > maxDist) {
maxDist = dist;
farV = cur;
}
vis[cur] = false;
}
int main() {
ios::sync_with_stdio(0); cin.tie(0);
cin >> V;
for(int i=0; i<V; i++) {
int x; cin >> x;
while(true) {
int y; cin >> y;
if(y == -1) break;
int w; cin >> w;
adj[x].push_back({y, w});
}
}
dfs(1, 0);
dfs(farV, 0);
cout << maxDist;
}
먼저 입력이 굉장히 크다.
처음에 무지성 가중인접행렬로 했다가 당연히 안됐다. -> 인접 리스트로 변환
트리 이기때문에 가중치를 조금 더 효율적으로 저장할 수 있을 거 같은데 일단 인접리스트에 스트럭쳐로 같이 저장했다.
입력을 어떻게 받는지도 중요하지만 중요한건 트리의 지름을 찾는 알고리즘이다.
트리의 지름을 찾는 알고리즘은 다음과 같다. 구사과님의 글을 참고했다.
- 아무 정점(`X`)를 잡고 가장 먼 정점(`Y`)를 찾는다.
- 정점 `Y`에서 가장 먼 정점(`Z`)를 찾는다.
- `Y`와 `Z`사이의 거리가 트리의 지름이다.
엄밀한 증명보다는 직관적으로 위 알고리즘을 이해해보자.
다음과 같은 트리가 있을 때, 트리의 지름을 잡고 잡아 당겨 펴보자.
트리 위에 아무 노드를 잡고 가장 먼 노드를 찾으면 트리의 지름의 한쪽 끝 중 하나(3, 5)로 수렴한다.
이는 n개의 모든 정점이 간선 n-1개로 연결되어있는 트리의 특성때문인데 만약 아무 노드를 잡고 가장 먼 노드를 찾았을 때 그 노드가 트리의 지름의 한 쪽 끝 중 하나로 수렴하지 않는다면 트리의 지름의 정의에 어긋나게 된다.
이렇게 찾은 트리의 지름의 한쪽 끝 점에서 가장 먼 정점을 찾으면 그 둘이 트리의 지름이 된다.
'Problem Solving > BOJ' 카테고리의 다른 글
[백준 - 3085] 사탕 게임 - C++, Python (1) | 2023.10.27 |
---|---|
[백준 - 1991] 트리 순회 - C++ (0) | 2023.10.27 |
[백준 - 11660] 구간 합 구하기 5 - C++ (0) | 2023.10.26 |
[백준 - 1992] 쿼드트리 - C++ (0) | 2023.10.24 |
[백준 - 1780] 종이의 개수 - C++ (0) | 2023.10.24 |