|
| 1 | +# 문제 |
| 2 | +가장 가까운 공통 조상 |
| 3 | +## 문제 원본 |
| 4 | +문제의 원본은 [여기서](https://www.acmicpc.net/problem/3584) 확인하세요. |
| 5 | + |
| 6 | +## 분류 |
| 7 | +* 그래프이론 |
| 8 | +* 탐색 |
| 9 | + |
| 10 | +# 풀이 |
| 11 | + |
| 12 | +각 노드에서 부모를 찾고 parents[]배열에 기록해둔다. 모든 노드에 대해 부모를 구한후 부모가 없는 노드(-1)를 찾는다. 이렇게 찾아진 노드를 시작으로 공통 부모 탐색을 시작한다. 자식노드에서 찾고자 하는 노드가 2개인 경우 혹은 1개 이면서 노드 자신이 찾고자 하는 노드인 경우, 해당 노드가 공통 조상이 된다. 하지만 가장가까운 조상 노드 하나만 구해야 한다. 따라서 절대 위의 조건에 걸릴이 없는 10000을 return하여 가장 가까운 조상 노드 하나만 출력하도록 한다. |
| 13 | + |
| 14 | +``` c++ |
| 15 | +#include <bits/stdc++.h> |
| 16 | + |
| 17 | +using namespace std; |
| 18 | + |
| 19 | +class Graph { |
| 20 | +public: |
| 21 | + int n; |
| 22 | + int root; |
| 23 | + vector<int>* adj; |
| 24 | + vector<int> parents; |
| 25 | + |
| 26 | + Graph(int n) { |
| 27 | + this->n = n; |
| 28 | + // this->root = root; |
| 29 | + this->adj = new vector<int>[n + 1]; |
| 30 | + parents = vector<int>(n+1); |
| 31 | + fill(parents.begin(), parents.end(), -1); |
| 32 | + } |
| 33 | + |
| 34 | + void insertEdge(int u, int v) { |
| 35 | + this->adj[u].push_back(v); |
| 36 | + } |
| 37 | + |
| 38 | + ~Graph() { |
| 39 | + delete[] adj; |
| 40 | + } |
| 41 | + |
| 42 | + // 각 노드의 부모를 찾아 parents 배열에 기록한다. |
| 43 | + void findRoots() { |
| 44 | + for (int i = 0; i < this->n + 1; i++) { |
| 45 | + int adjSize = this->adj[i].size(); |
| 46 | + for (int j = 0; j < adjSize; j++) { |
| 47 | + int v = this->adj[i][j]; |
| 48 | + |
| 49 | + parents[v] = i; |
| 50 | + } |
| 51 | + } |
| 52 | + |
| 53 | + // 부모가 없는 경우 (-1) : 최상위 Root |
| 54 | + for (int i = 1; i < n + 1; i++) { |
| 55 | + if (parents[i] == -1) { |
| 56 | + this->root = i; |
| 57 | + } |
| 58 | + } |
| 59 | + } |
| 60 | +}; |
| 61 | + |
| 62 | + |
| 63 | +int NCA(Graph* g, int u, int finding1, int finding2) { |
| 64 | + int count = 0; |
| 65 | + |
| 66 | + |
| 67 | + for (int i = 0; i < g->adj[u].size(); i++) { |
| 68 | + count += NCA(g, g->adj[u][i], finding1, finding2); |
| 69 | + } |
| 70 | + |
| 71 | + // 왼쪽 조건 : 둘다 자식노드에 있는 경우, 오른쪽 조건 : 하나는 자식노드에 하나는 자신의 노드인경우 |
| 72 | + if (count == 2 || (count == 1 && (u == finding1 || u == finding2))) { |
| 73 | + cout << u << "\n"; |
| 74 | + return 10000; // 위의 조건에 걸리지 않을 수를 주어 처음 한번만 출력하게 한다. |
| 75 | + } |
| 76 | + |
| 77 | + if (finding1 == u || finding2 == u) { |
| 78 | + return count + 1; |
| 79 | + } |
| 80 | + else { |
| 81 | + return count; |
| 82 | + } |
| 83 | + |
| 84 | +} |
| 85 | + |
| 86 | + |
| 87 | +int main(void) { |
| 88 | + ios::sync_with_stdio(false); |
| 89 | + cin.tie(0); cout.tie(0); |
| 90 | + |
| 91 | + int t; |
| 92 | + cin >> t; |
| 93 | + for (int z = 0; z < t; z++) { |
| 94 | + int nV; |
| 95 | + cin >> nV; |
| 96 | + |
| 97 | + Graph* g = new Graph(nV); |
| 98 | + |
| 99 | + for (int i = 0; i < nV - 1; i++) { |
| 100 | + int u, v; |
| 101 | + cin >> u >> v; |
| 102 | + |
| 103 | + g->insertEdge(u, v); |
| 104 | + } |
| 105 | + |
| 106 | + int u, v; |
| 107 | + cin >> u >> v; |
| 108 | + |
| 109 | + // 최상위 루트를 찾고 |
| 110 | + g->findRoots(); |
| 111 | + |
| 112 | + // 최상위 루트를 시작으로 Nearest Common Ascestor를 찾는다. |
| 113 | + NCA(g, g->root, u, v); |
| 114 | + |
| 115 | + delete g; |
| 116 | + } |
| 117 | + |
| 118 | + return 0; |
| 119 | +} |
| 120 | +``` |
0 commit comments