티스토리 뷰
트리에서 가장 긴 경로를 구하는 문제
문제
트리(tree)는 사이클이 없는 무방향 그래프이다. 트리에서는 어떤 두 노드를 선택해도 둘 사이에 경로가 항상 하나만 존재하게 된다. 트리에서 어떤 두 노드를 선택해서 양쪽으로 쫙 당길 때, 가장 길게 늘어나는 경우가 있을 것이다. 이럴 때 트리의 모든 노드들은 이 두 노드를 지름의 끝 점으로 하는 원 안에 들어가게 된다.
이런 두 노드 사이의 경로의 길이를 트리의 지름이라고 한다. 정확히 정의하자면 트리에 존재하는 모든 경로들 중에서 가장 긴 것의 길이를 말한다.
입력으로 루트가 있는 트리를 가중치가 있는 간선들로 줄 때, 트리의 지름을 구해서 출력하는 프로그램을 작성하시오. 아래와 같은 트리가 주어진다면 트리의 지름은 45가 된다.
트리의 노드는 1부터 n까지 번호가 매겨져 있다.
입력
파일의 첫 번째 줄은 노드의 개수 n(1 ≤ n ≤ 10,000)이다. 둘째 줄부터 n-1개의 줄에 각 간선에 대한 정보가 들어온다. 간선에 대한 정보는 세 개의 정수로 이루어져 있다. 첫 번째 정수는 간선이 연결하는 두 노드 중 부모 노드의 번호를 나타내고, 두 번째 정수는 자식 노드를, 세 번째 정수는 간선의 가중치를 나타낸다. 간선에 대한 정보는 부모 노드의 번호가 작은 것이 먼저 입력되고, 부모 노드의 번호가 같으면 자식 노드의 번호가 작은 것이 먼저 입력된다. 루트 노드의 번호는 항상 1이라고 가정하며, 간선의 가중치는 100보다 크지 않은 양의 정수이다.
출력
첫째 줄에 트리의 지름을 출력한다.
풀이
DFS로 재귀 탐색하면서 가중치 계산을 하면 될 거라고 생각했는데 처음에 짰던 코드는 DFS 시작 지점에 따라 답이 맞거나 틀려서 보완이 필요했습니다. 찾아보니 DFS를 2번 돌리는 것이 핵심이었습니다.
임의의 지점에서 첫 번째 DFS로 가장 깊은 곳까지 간 뒤 거기에서 다시 DFS로 가장 먼 지점을 찾으면 트리에서 가장 긴 경로가 됩니다. DFS 탐색을 한다면 어디에서 출발을 하든 가장 깊은 끝에는 다다르게 되고 그곳이 지름의 한 쪽 끝이 됩니다. 지름의 한 쪽 끝에서 다시 DFS 탐색을 하면 또 가장 깊은 곳으로 가게 될 것이고 거기가 지름의 반대쪽 끝점이 되는 것이죠. 여기까지 생각을 못 해서 거의 다 와서 틀렸네용 ㅎ;
코드
#include <iostream>
#include <vector>
using namespace std;
int answer = 0; //지름의 길이
int endPoint = 0; //지름의 한 쪽 끝점
void dfs(vector<vector<pair<int, int>>>& tree, vector<bool>& visited, int cur, int weight)
{
for (int i = 0; tree[cur].size() > i; i++)
{
auto next = tree[cur][i].first;
if (!visited[next])
{
visited[next] = true;
dfs(tree, visited, next, weight + tree[cur][i].second);
}
}
//첫 번째 DFS에서 끝에 다다르면 endPoint 정보를 저장한다.
//endPoint에서 시작한 두 번째 DFS에서 끝에 다다르면 지름의 길이를 구할 수 있다.
if (answer < weight)
{
answer = weight;
endPoint = cur;
}
}
int main()
{
int N;
cin >> N;
vector<vector<pair<int, int>>> tree(N + 1); //pair<연결노드, 가중치>
for (int i = 0; N - 1 > i; i++)
{
int parent, child, weight;
cin >> parent >> child >> weight;
tree[parent].emplace_back(make_pair(child, weight));
tree[child].emplace_back(make_pair(parent, weight));
}
vector<bool> visited(N + 1, false);
visited[1] = true;
dfs(tree, visited, 1, 0); //지름의 한 쪽 끝점을 찾기 위한 첫 번째 DFS
visited.assign(N + 1, false);
visited[endPoint] = true;
dfs(tree, visited, endPoint, 0); //지름의 길이를 구하기 위한 두 번째 DFS
cout << answer;
return 0;
}
'알고리즘 문제 풀이 > DFS BFS' 카테고리의 다른 글
[C++] 백준 온라인 저지 9466번 텀 프로젝트 풀이 (0) | 2021.11.20 |
---|---|
[C++] 백준 온라인 저지 1167번 트리의 지름 풀이 (0) | 2021.11.19 |
[C++] 백준 온라인 저지 1937번 욕심쟁이 판다 풀이 (0) | 2021.11.17 |
[C++] 백준 온라인 저지 2573번 빙산 풀이 (0) | 2021.11.14 |
[C++] 프로그래머스 네트워크 풀이 (0) | 2021.11.14 |
- Total
- Today
- Yesterday
- c언어
- 컴퓨터공부
- dp
- 캐나다
- 백준
- 기초
- greedy
- BFS
- 다이나믹프로그래밍
- 해커랭크
- c++
- 너비우선탐색
- 컴퓨터
- C언어기초
- 코딩공부
- 컴퓨터사이언스
- 깊이우선탐색
- 프로그래머스
- 그리디
- DFS
- 문제풀이
- 알고리즘
- 애플
- 아이패드
- 하드웨어
- 프로그래밍
- 영어공부
- hackerrank
- 스위프트플레이그라운드
- 캐나다생활
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |