본문 바로가기
문제/백준

c++ 백준_1167_"트리의 지름"

by 나 진짜 못차마 2023. 6. 13.
728x90

https://www.acmicpc.net/problem/1167

 

1167번: 트리의 지름

트리가 입력으로 주어진다. 먼저 첫 번째 줄에서는 트리의 정점의 개수 V가 주어지고 (2 ≤ V ≤ 100,000)둘째 줄부터 V개의 줄에 걸쳐 간선의 정보가 다음과 같이 주어진다. 정점 번호는 1부터 V까지

www.acmicpc.net

 

정점이 100,000 개라서

무조건 n² 이 되게 하면 안될 거 같았다.

그래도 하지말라는 거 괜히 해보기 ㅎ

leaf 노드를 시작으로 다 DFS를 돌려보니 역시

시간초과

그래서 kruskal 이니,

노드의 가중치를 이전 노드에서 더해서 어쩌구,

가지치기 처럼 해보니 마니

하면서

혼자 예제를 만들었는데

정점이 6개인 트리이다.

이 트리를 보며

1 에서 dfs를 시작해서 (1 - 2)의 가중치를 어떻게 저장하며

(2 - 1 - 6 - 5 ) = 15 의 가중치를 어떻게 만들지 고민했다.

1 에서 DFS를 시작해 가장 거리가 먼 노드(5) 에 도착 후,

다시 5에서 DFS 를 시작하면 (2) 에 도달해 15 반환이 되었다.

이런 얼렁뚱땅 방법이 되길래 코드를 작성해보고

던지는 식으로 다시 제출했는데

띠링?

기분은 좋았지만 찝찝함..

급똥 해결 후 쾌락 but 덜 닦은 느낌

구글에 트리 지름 구하는 공식을 검색해봤다.

jooon na 감동이여야할지,

이게?

라고 반응해야할지

트리의 지름 구하는 공식 중 하나는 정확히 이런 방법이였다 !

왜인가 싶어 설명을 보니

하나 같이 이해를 못하겠다 !

그래서 혼자 나름 내 코드과 왜 답이 되는지 이해를 해보았다.

트리라는 점을 먼저 인지하고,

(트리의 성질)

노드의 한 점에서 DFS를 시작해 가장 먼 노드로 이동하였다.

그럼 트리이니 root 노드가 존재하기 때문에

1을 root라 가정하고 오른팔에서 가장 큰 거리를 가져온 격이 된다.

그럼 1의 왼쪽도 봐야한다.

이미 1의 오른쪽에서 가장 큰 거리(가중치)를 구했으니 그 마지막 노드(5) 에서

시작하면 1을 통해 자연스레 왼팔로 스근하고 부드럽게 넘어가

트리를 쭉 펼쳤을 때의 가장 큰 지름이 되지

아니 한가

하는

작고 귀여운 나만의 생각.

위의 경우에는 루트가 이진 트리지만

루트(1)에서 가지가 많아도 먼저 가장 먼 거리를 골랐기 때문에

두번째, 다시 가장 먼 노드에서 DFS할 때는

거기서 이미 구한 첫번째 DFS + 한 곳 방향으로 밖에 가지 못한다.

(지름이기 때문에)

or

첫번째 DFS에서 구한 길이 있을 것이다.

그럼 이미 그 방면은 다 체크한게 된다.

그래서 다시 두번째 DFS를 진행할 때

루트 (1)을 지나지 않고

가장 먼 거리를 만들 수 있는 가중치가 있다면

그쪽으로 확인하면 된다.

가슴으로는 와닿는데 표현이 안되네...☆

새벽에 억지로 이해안되는 거 이해하려니

내가 뭔 소리하는지 모르겠다

이래서 설명을 할 수 있을 레벨이 되어야 된다.

코드는 간단한데 심오하구만

 

 

#include <iostream>
#include <vector>
using namespace std;

vector<vector<pair<int, int>>> node(100001);
vector<bool> visit(100001, false);

int longest = 0;
int last = 0;

void dfs(int u, int weight) {

	visit[u] = true;

	if (weight > longest) {
		longest = weight;
		last = u;
	}

	for (int i = 0; i < node[u].size(); i++) {
		if (visit[node[u][i].first])
			continue;

		dfs(node[u][i].first, weight + node[u][i].second);
	}
}

int main(void) {

	int V;
	cin >> V;


	int u, v, weight;

	for (int i = 0; i < V; i++) {

		cin >> u;

		while (1) {
			cin >> v;
			if (v == -1)
				break;
			cin >> weight;

			node[u].push_back(make_pair(v, weight));
		}
	}

	dfs(1, 0);

	for (int i = 1; i <= V; i++) {
		visit[i] = false;
	}
	dfs(last, 0);

	cout << longest;

}
728x90

'문제 > 백준' 카테고리의 다른 글

c++ 백준_1405_"미친 로봇"  (0) 2023.06.15
c++ 백준_1715_"카드 정렬하기"  (0) 2023.06.15
c++ 백준_1918_"후위 표기식"  (2) 2023.06.13
c++ 백준_1132_"합"  (0) 2023.06.13
c++ 백준_15686_"치킨 배달"  (2) 2023.06.13