반응형
문제 출처 :
https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV15PTkqAPYCFAYD
알고리즘 분석 :
문제 해결에 필요한 사항
1. BFS
2. LCA
이 문제는 2가지 방법으로 해결 가능하다.
도착지점 두개를 큐에 집어넣고 BFS를 돌려 이미 visit한곳에 다른 정점에서 오는 것이 visit를 하게 된다면
그것이 가장 가까운 공통 조상이 된다.
그 외에는 LCA 알고리즘을 이용하면 문제해결을 할 수 있다.
소스 코드 :
<< LCA 알고리즘이 없이 해결 >>
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | /* https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV15PTkqAPYCFAYD 이 문제는 사실 lca 알고리즘을 이용하지 않아도 된다. 그 이유는 lca에서 dp를 이용하는데 여러 쿼리가 계속 들어올 때 빠르게 해결하기 위해 전처리를 하는 것이고 현재 문제에서는 한번만 답을 내면 되기 때문에 visit배열을 이용하여 해결 할 수 있다. 최소 공통 조상을 찾기위한 노드 a,b를 queue에 push하고 찾아가다가 visit를 방문한 곳에 한번 더 방문하려한다면 그곳이 최소 공통 조상이다. */ #include <iostream> #define swap(a,b){int t = a; a = b; b = t;} #define MAX_NODE 10002 int visit[MAX_NODE]; int visitCnt; int queue[MAX_NODE]; int first, last; class _vector { public: int sz; int capacity; int *vc; _vector() { capacity = 8; sz = 0; vc = new int[capacity]; } ~_vector() { delete[] vc; } void push_back(int val) { if (sz == capacity) { int *tmp = new int[capacity]; for (int i = 0; i < capacity; i++) tmp[i] = vc[i]; capacity *= 2; delete[] vc; vc = new int[capacity]; for (int i = 0; i < capacity; i++) vc[i] = tmp[i]; } vc[sz++] = val; } void clear() { capacity = 8; sz = 0; delete[] vc; vc = new int[capacity]; } int size() { return sz; } bool empty() { return sz ? false : true; } int &operator [](int i) { return vc[i]; } }; void init() { visitCnt++; first = last = 0; } int main() { freopen("input.txt", "r", stdin); int tCase; scanf("%d", &tCase); for (int tc = 1; tc <= tCase; tc++) { init(); _vector ctop[MAX_NODE]; // 부모에서 자식 간선 _vector ptoc[MAX_NODE]; // 자식에서 부모 간선 int v, e, a, b; scanf("%d %d %d %d", &v, &e, &a, &b); for (int i = 0; i < e; i++) { int par, child; scanf("%d %d", &par, &child); ctop[par].push_back(child); ptoc[child].push_back(par); } int lca = -1; queue[last++] = a; queue[last++] = b; while (first < last) { int here = queue[first++]; if (visit[here] == visitCnt) { lca = here; break; } visit[here] = visitCnt; for (int i = 0; i < ptoc[here].size(); i++) { int next = ptoc[here][i]; queue[last++] = next; } } int cnt = 0; first = last = 0; queue[last++] = lca; while (first < last) { int here = queue[first++]; cnt++; for (int i = 0; i < ctop[here].size(); i++) { int next = ctop[here][i]; queue[last++] = next; } } printf("#%d %d %d\n", tc, lca, cnt); } return 0; } | cs |
<< LCA 알고리즘 이용 >>
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | /* https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV15PTkqAPYCFAYD https://www.crocus.co.kr/660 lca 알고리즘을 이용하면 최소 공통 조상을 찾을 수 있다. 이때 해당하는 lca에서 나오는 subtree의 노드수는 vc벡터를 하나 더 만들어 bfs로 해결한다. */ #include <iostream> #include <cstdio> #include <vector> #include <cmath> #include <queue> #define swap(a,b){int t = a; a = b; b = t;} #define MAX_NODE 50002 using namespace std; int depth[MAX_NODE]; int ac[MAX_NODE][20]; typedef pair<int, int> pii; vector<int> graph[MAX_NODE]; vector<int> vc[MAX_NODE]; int max_level; void init() { for (int i = 0; i < MAX_NODE; i++) vc[i].clear(), graph[i].clear(); } void getTree(int here, int parent) { depth[here] = depth[parent] + 1; ac[here][0] = parent; max_level = (int)floor(log2(MAX_NODE)); for (int i = 1; i <= max_level; i++) { int tmp = ac[here][i - 1]; ac[here][i] = ac[tmp][i - 1]; } int len = graph[here].size(); for (int i = 0; i < len; i++) { int there = graph[here][i]; if (there != parent) getTree(there, here); } } int main() { int tCase; scanf("%d", &tCase); for (int tc = 1; tc <= tCase; tc++) { init(); int n, m, a, b; scanf("%d %d %d %d", &n, &m, &a, &b); for (int i = 0; i < m; i++) { int from, to; scanf("%d %d", &from, &to); graph[from].push_back(to); graph[to].push_back(from); vc[from].push_back(to); } depth[0] = -1; getTree(1, 0); if (depth[a] != depth[b]) { if (depth[a] > depth[b]) swap(a, b); for (int i = max_level; i >= 0; i--) { if (depth[a] <= depth[ac[b][i]]) b = ac[b][i]; } } int lca = a; if (a != b) { for (int i = max_level; i >= 0; i--) { if (ac[a][i] != ac[b][i]) { a = ac[a][i]; b = ac[b][i]; } lca = ac[a][i]; } } queue<int> q; q.push(lca); int subTree = 0; while (!q.empty()) { int here = q.front(); q.pop(); subTree++; for (int i = 0; i < vc[here].size(); i++) q.push(vc[here][i]); } printf("#%d %d %d\n", tc, lca, subTree); } return 0; } | cs |
반응형
'Applied > 알고리즘 문제풀이' 카테고리의 다른 글
[3780번] Corporative Network (0) | 2019.10.17 |
---|---|
[5397번] 키로거 (0) | 2019.10.10 |
[Programmers] 저울 (0) | 2019.09.10 |
[1249번] 보급로 (0) | 2019.09.09 |
[Programmers] 영어 끝말잇기 (0) | 2019.09.05 |