https://www.acmicpc.net/problem/15681
15681번: 트리와 쿼리
트리의 정점의 수 N과 루트의 번호 R, 쿼리의 수 Q가 주어진다. (2 ≤ N ≤ 105, 1 ≤ R ≤ N, 1 ≤ Q ≤ 105) 이어 N-1줄에 걸쳐, U V의 형태로 트리에 속한 간선의 정보가 주어진다. (1 ≤ U, V ≤ N, U ≠ V)
www.acmicpc.net
알고리즘의 기본 틀은 아래와 같습니다.
BFS수행 후, 각 정점의 부모 노드를 찾음.
- BFS를 수행하면서 Leaf 노드는 서브 트리 크기를 1로 설정
- 각 정점의 서브 트리의 크기를 구함
- 서브 트리의 크기 = 자식 서브 트리의 합 + 1
재귀와memoization를 이용
전체 코드는 아래와 같습니다.
#include <bits/stdc++.h> using namespace std; // BFS 수행 후, 각 정점의 부모 노드를 찾음 // 자식이 없는 트리의 서브트리의 크기를 1로 설정 // 부모 서브트리의 크기는 자식 서브 트리의 합 + 1 int p[100010]; // p[i]는 i번째 정점의 부모 노드 번호 int s[100010]; // s[i]는 i번째 정점을 루트로 하는 서브트리의 크기 int n, r, q; int tree_size(vector<vector<int>>& linked, int v){ // 정점 v를 루트로 하는 서브 트리 크기를 반환하는 함수 if(s[v] != 0){ // 이미 서브 트리의 크기가 계산된 경우 return s[v]; }else{ // 서브 트리의 값이 계산되지 않은 경우 int sum = 0; // 정점 v를 루트로 하는 서브 트리의 크기 for(auto nxt : linked[v]){ // 자식 서브 트리의 크기 합을 구함 if(nxt == p[v]) continue; // 부모 노드인 경우 continue sum += tree_size(linked, nxt); } s[v] = sum + 1; // 루트를 포함 시킴 return s[v]; } } int main(){ ios::sync_with_stdio(0); cin.tie(0); cin >> n >> r >> q; vector<vector<int>> linked(n + 1); // 인접 리스트 for(int i = 0; i < n - 1; i++){ // 인접 리스트 입력 받음 int u, v; cin >> u >> v; linked[u].push_back(v); linked[v].push_back(u); } // BFS 수행 queue<int> q1; q1.push(r); p[r] = -1; while(!q1.empty()){ int cur = q1.front(); q1.pop(); bool leaf = true; for(auto nxt : linked[cur]){ if(nxt == p[cur]) continue; leaf = false; // 인접한 노드 중 방문하지 않은 노드가 존재하는 경우 leaf 노드가 아님 q1.push(nxt); p[nxt] = cur; } if(leaf) s[cur] = 1; // leaf 노드인 경우 서브 트리의 크기를 1로 설정 } while(q--){ int v; cin >> v; cout << tree_size(linked, v) << "\n"; // 정점 v를 루트로 하는 서브 트리의 크기 출력 } }
'Algorithm > Tree' 카테고리의 다른 글
[SW Expert Academy 1248번] 공통 조상 (0) | 2022.07.03 |
---|---|
[백준 20955번] 민서의 응급 수술 (C++) (0) | 2022.06.05 |
[백준 4803번] 트리 (C++) (0) | 2022.06.04 |