컴퓨터 사이언스/1고리즘

백준 1135 : 뉴스 전하기

저세상 개발자 2021. 8. 21. 19:15

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

 

1135번: 뉴스 전하기

민식이는 회사의 매니저이다. 그리고, 민식이는 회사의 중요한 뉴스를 모든 직원에게 빠르게 전달하려고 한다. 민식이의 회사는 트리 구조이다. 모든 직원은 정확하게 한 명의 직속 상사가 있다

www.acmicpc.net

 

tree dp 문제다. 탑다운 방식으로 구현했다.

 

1. 자식 노드로 뉴스를 전하면 그 다음 턴부터 자식 노드에서도 병렬적으로 그 자식노드에게 뉴스를 전하므로, 가장 최소한의 시간으로 목적을 달성하기 위해선 가장 시간이 오래 걸리는 노드부터 소식을 전달해야 한다.

  -> 이 관점에서 보면 그리디 문제이기도 하다.

 

2. 현재 노드에서 모든 자식노드들에 뉴스를 전하는데 걸리는 시간은

(각각의 자식노드가 자신의 모든 자식노드들에 뉴스를 전달하는 시간) + (현재 노드에서 해당 노드에 뉴스를 전달한 순서 i) 중 가장 큰 값이다.

예를 들면, 현재 노드의 자식노드가 3개 있고 각각의 자식노드가 자신의 자식노드들에게 뉴스를 전달하는데 걸리는 시간이 각각

 

0번 째 자식 노드 -> 3분,

1번 째 자식 노드 -> 3분,

2번 째 자식 노드 -> 4분 이라면,

1번 로직에 의해 2번째 자식노드, 0번째 자식노드, 1번째 자식노드 순으로 소식을 전달해야 하고 각각의 자식노드들에 소식을 전달하는데 1분이 소요되므로 각각의 자식노드들이 뉴스를 전하는 시간은 

 

2번 째 자식 노드 -> 4분 + 1분 = 5분,

0번 째 자식 노드 -> 3분 + 2분 = 5분,

1번 째 자식 노드 -> 3분 + 3분 = 6분 이 되므로, 해당 노드에서 모든 자식노드들에 뉴스를 전하는 최소 시간은 세 개의 자식 노드들 중 가장 오랜 시간이 걸리는 6분이 된다.

 

3. 현재 노드의 자식노드를 루트 노드로 하는 서브트리도 1, 2번 로직과 같은 방법으로 최소 시간을 계산할 수 있다.

  -> 어떠한 큰 문제를 작은 문제들로 나누어 해결할 수 있다. -> DP로 해결할 수 있다.

 

4. 한 번 계산한 노드에서 중복하여 계산하지 않도록 메모이제이션을 사용한다.

 

코드로 구현하면 아래와 같다.

 

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int n;
vector<int> child[50];
int tree_dp[50];

int DP(int cur) {
	// 메모이제이션 되어있을 경우 해당 값 리턴
	if (tree_dp[cur] != - 1) return tree_dp[cur];
	// 자식 노드가 없다면(리프노드라면) 걸리는 시간이 없으므로 0을 메모이제이션하고 리턴
	if (!child[cur].size()) return tree_dp[cur] = 0;

	// 현재 노드의 각각의 자식 노드들이 자신의 자식 노드들에 뉴스를 전파하는데 걸리는 시간을 담을 벡터 변수
	vector<int> cur_child_cost;

	// 탑다운 재귀 방식으로 자식 노드들의 최소 시간을 계산, 리턴받아 cur_child_cost에 저장
	for (int i = 0; i < child[cur].size(); i++) {
		cur_child_cost.push_back(DP(child[cur][i]));
	}

	// 가장 오랜 시간이 걸리는 자식 노드부터 뉴스를 전달하기 위하여 내림차순 sort 수행
	sort(cur_child_cost.begin(), cur_child_cost.end(), greater<>());
	// 뉴스를 전하는 순서에 따라 추가적으로 소요되는 시간 더해줌
	for (int i = 0; i < cur_child_cost.size(); i++) {
		cur_child_cost[i] += i + 1;
	}

	// 현재 노드의 자식노드들 중에서 가장 오래 걸리는 시간이 최소 시간이므로 메모이제이션 하고 리턴
	return tree_dp[cur] = *max_element(cur_child_cost.begin(), cur_child_cost.end());
}

void solution() {
	int tmp;
	cin >> n;
	cin >> tmp;
	for (int i = 1; i < n; i++)
		cin >> tmp, child[tmp].push_back(i);

	for (int i = 0; i < n; i++)
		tree_dp[i] = -1;

	cout << DP(0);
}

int main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	solution();

	return 0;
}
메모리: 2024 kb 시간: 0 ms