1/*
2 * μμ μ λ ¬ (Topological Sort)
3 * Kahn's Algorithm, DFS-based, Cycle Detection
4 *
5 * DAG(Directed Acyclic Graph)μμ μ μ λ€μ μ ν μμλ₯Ό μ°Ύμ΅λλ€.
6 */
7
8#include <iostream>
9#include <vector>
10#include <queue>
11#include <stack>
12#include <algorithm>
13
14using namespace std;
15
16// =============================================================================
17// 1. Kahn's Algorithm (BFS κΈ°λ°)
18// =============================================================================
19
20vector<int> topologicalSortKahn(int n, const vector<vector<int>>& adj) {
21 vector<int> indegree(n, 0);
22
23 // μ§μ
μ°¨μ κ³μ°
24 for (int u = 0; u < n; u++) {
25 for (int v : adj[u]) {
26 indegree[v]++;
27 }
28 }
29
30 // μ§μ
μ°¨μκ° 0μΈ μ μ μ νμ μΆκ°
31 queue<int> q;
32 for (int i = 0; i < n; i++) {
33 if (indegree[i] == 0) {
34 q.push(i);
35 }
36 }
37
38 vector<int> result;
39 while (!q.empty()) {
40 int node = q.front();
41 q.pop();
42 result.push_back(node);
43
44 for (int neighbor : adj[node]) {
45 indegree[neighbor]--;
46 if (indegree[neighbor] == 0) {
47 q.push(neighbor);
48 }
49 }
50 }
51
52 // μ¬μ΄ν΄μ΄ μμΌλ©΄ λͺ¨λ μ μ μ λ°©λ¬Έν μ μμ
53 if ((int)result.size() != n) {
54 return {}; // μ¬μ΄ν΄ μ‘΄μ¬
55 }
56
57 return result;
58}
59
60// =============================================================================
61// 2. DFS κΈ°λ° μμ μ λ ¬
62// =============================================================================
63
64void topoDFS(int node, const vector<vector<int>>& adj,
65 vector<bool>& visited, stack<int>& st) {
66 visited[node] = true;
67
68 for (int neighbor : adj[node]) {
69 if (!visited[neighbor]) {
70 topoDFS(neighbor, adj, visited, st);
71 }
72 }
73
74 st.push(node);
75}
76
77vector<int> topologicalSortDFS(int n, const vector<vector<int>>& adj) {
78 vector<bool> visited(n, false);
79 stack<int> st;
80
81 for (int i = 0; i < n; i++) {
82 if (!visited[i]) {
83 topoDFS(i, adj, visited, st);
84 }
85 }
86
87 vector<int> result;
88 while (!st.empty()) {
89 result.push_back(st.top());
90 st.pop();
91 }
92
93 return result;
94}
95
96// =============================================================================
97// 3. μ¬μ΄ν΄ νμ§ (DFS)
98// =============================================================================
99
100bool hasCycleDFS(int node, const vector<vector<int>>& adj,
101 vector<int>& color) {
102 color[node] = 1; // λ°©λ¬Έ μ€ (νμ)
103
104 for (int neighbor : adj[node]) {
105 if (color[neighbor] == 1) {
106 return true; // λ°± μ£μ§ λ°κ²¬ (μ¬μ΄ν΄)
107 }
108 if (color[neighbor] == 0 && hasCycleDFS(neighbor, adj, color)) {
109 return true;
110 }
111 }
112
113 color[node] = 2; // λ°©λ¬Έ μλ£ (κ²μμ)
114 return false;
115}
116
117bool hasCycle(int n, const vector<vector<int>>& adj) {
118 vector<int> color(n, 0); // 0: λ―Έλ°©λ¬Έ, 1: λ°©λ¬Έ μ€, 2: μλ£
119
120 for (int i = 0; i < n; i++) {
121 if (color[i] == 0 && hasCycleDFS(i, adj, color)) {
122 return true;
123 }
124 }
125
126 return false;
127}
128
129// =============================================================================
130// 4. λͺ¨λ μμ μ λ ¬ μμ μ°ΎκΈ°
131// =============================================================================
132
133void allTopoSorts(vector<vector<int>>& adj, vector<int>& indegree,
134 vector<int>& result, vector<bool>& visited,
135 vector<vector<int>>& allResults, int n) {
136 bool found = false;
137
138 for (int i = 0; i < n; i++) {
139 if (indegree[i] == 0 && !visited[i]) {
140 // μ΄ μ μ μ ν
141 visited[i] = true;
142 result.push_back(i);
143
144 for (int neighbor : adj[i]) {
145 indegree[neighbor]--;
146 }
147
148 allTopoSorts(adj, indegree, result, visited, allResults, n);
149
150 // λ°±νΈλνΉ
151 visited[i] = false;
152 result.pop_back();
153 for (int neighbor : adj[i]) {
154 indegree[neighbor]++;
155 }
156
157 found = true;
158 }
159 }
160
161 if (!found && (int)result.size() == n) {
162 allResults.push_back(result);
163 }
164}
165
166vector<vector<int>> findAllTopologicalSorts(int n, const vector<vector<int>>& adj) {
167 vector<int> indegree(n, 0);
168 for (int u = 0; u < n; u++) {
169 for (int v : adj[u]) {
170 indegree[v]++;
171 }
172 }
173
174 vector<int> result;
175 vector<bool> visited(n, false);
176 vector<vector<int>> allResults;
177 vector<vector<int>> adjCopy = adj;
178
179 allTopoSorts(adjCopy, indegree, result, visited, allResults, n);
180
181 return allResults;
182}
183
184// =============================================================================
185// 5. κ³Όλͺ© μκ° μμ (Course Schedule)
186// =============================================================================
187
188bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
189 vector<vector<int>> adj(numCourses);
190 vector<int> indegree(numCourses, 0);
191
192 for (auto& [course, prereq] : prerequisites) {
193 adj[prereq].push_back(course);
194 indegree[course]++;
195 }
196
197 queue<int> q;
198 for (int i = 0; i < numCourses; i++) {
199 if (indegree[i] == 0) {
200 q.push(i);
201 }
202 }
203
204 int count = 0;
205 while (!q.empty()) {
206 int node = q.front();
207 q.pop();
208 count++;
209
210 for (int neighbor : adj[node]) {
211 indegree[neighbor]--;
212 if (indegree[neighbor] == 0) {
213 q.push(neighbor);
214 }
215 }
216 }
217
218 return count == numCourses;
219}
220
221vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
222 vector<vector<int>> adj(numCourses);
223 vector<int> indegree(numCourses, 0);
224
225 for (auto& [course, prereq] : prerequisites) {
226 adj[prereq].push_back(course);
227 indegree[course]++;
228 }
229
230 queue<int> q;
231 for (int i = 0; i < numCourses; i++) {
232 if (indegree[i] == 0) {
233 q.push(i);
234 }
235 }
236
237 vector<int> result;
238 while (!q.empty()) {
239 int node = q.front();
240 q.pop();
241 result.push_back(node);
242
243 for (int neighbor : adj[node]) {
244 indegree[neighbor]--;
245 if (indegree[neighbor] == 0) {
246 q.push(neighbor);
247 }
248 }
249 }
250
251 if ((int)result.size() != numCourses) {
252 return {};
253 }
254
255 return result;
256}
257
258// =============================================================================
259// 6. μΈκ³μΈ μ¬μ (Alien Dictionary)
260// =============================================================================
261
262string alienOrder(vector<string>& words) {
263 // κ·Έλν ꡬμ±
264 unordered_map<char, unordered_set<char>> adj;
265 unordered_map<char, int> indegree;
266
267 // λͺ¨λ λ¬Έμ μ΄κΈ°ν
268 for (const string& word : words) {
269 for (char c : word) {
270 if (indegree.find(c) == indegree.end()) {
271 indegree[c] = 0;
272 }
273 }
274 }
275
276 // μΈμ ν λ¨μ΄ λΉκ΅νμ¬ μμ κ²°μ
277 for (int i = 0; i < (int)words.size() - 1; i++) {
278 string& w1 = words[i];
279 string& w2 = words[i + 1];
280
281 // μλͺ»λ μμ μ²΄ν¬ (prefixκ° λ λ€μ μ¬ μ μμ)
282 if (w1.length() > w2.length() &&
283 w1.substr(0, w2.length()) == w2) {
284 return "";
285 }
286
287 for (int j = 0; j < (int)min(w1.length(), w2.length()); j++) {
288 if (w1[j] != w2[j]) {
289 if (adj[w1[j]].find(w2[j]) == adj[w1[j]].end()) {
290 adj[w1[j]].insert(w2[j]);
291 indegree[w2[j]]++;
292 }
293 break;
294 }
295 }
296 }
297
298 // μμ μ λ ¬
299 queue<char> q;
300 for (auto& [c, deg] : indegree) {
301 if (deg == 0) {
302 q.push(c);
303 }
304 }
305
306 string result;
307 while (!q.empty()) {
308 char c = q.front();
309 q.pop();
310 result += c;
311
312 for (char next : adj[c]) {
313 indegree[next]--;
314 if (indegree[next] == 0) {
315 q.push(next);
316 }
317 }
318 }
319
320 if (result.length() != indegree.size()) {
321 return ""; // μ¬μ΄ν΄ μ‘΄μ¬
322 }
323
324 return result;
325}
326
327// =============================================================================
328// ν
μ€νΈ
329// =============================================================================
330
331void printVector(const vector<int>& v) {
332 cout << "[";
333 for (size_t i = 0; i < v.size(); i++) {
334 cout << v[i];
335 if (i < v.size() - 1) cout << ", ";
336 }
337 cout << "]";
338}
339
340int main() {
341 cout << "============================================================" << endl;
342 cout << "μμ μ λ ¬ μμ " << endl;
343 cout << "============================================================" << endl;
344
345 // ν
μ€νΈ κ·Έλν
346 // 5 β 0 β 4
347 // β β
348 // 2 β 3 β 1
349 int n = 6;
350 vector<vector<int>> adj(n);
351 adj[5] = {0, 2};
352 adj[4] = {0, 1};
353 adj[2] = {3};
354 adj[3] = {1};
355
356 // 1. Kahn's Algorithm
357 cout << "\n[1] Kahn's Algorithm (BFS)" << endl;
358 auto result1 = topologicalSortKahn(n, adj);
359 cout << " μμ μ λ ¬: ";
360 printVector(result1);
361 cout << endl;
362
363 // 2. DFS κΈ°λ°
364 cout << "\n[2] DFS κΈ°λ° μμ μ λ ¬" << endl;
365 auto result2 = topologicalSortDFS(n, adj);
366 cout << " μμ μ λ ¬: ";
367 printVector(result2);
368 cout << endl;
369
370 // 3. μ¬μ΄ν΄ νμ§
371 cout << "\n[3] μ¬μ΄ν΄ νμ§" << endl;
372 cout << " νμ¬ κ·Έλν: " << (hasCycle(n, adj) ? "μ¬μ΄ν΄ μμ" : "DAG") << endl;
373
374 vector<vector<int>> cycleAdj(3);
375 cycleAdj[0] = {1};
376 cycleAdj[1] = {2};
377 cycleAdj[2] = {0};
378 cout << " μ¬μ΄ν΄ κ·Έλν: " << (hasCycle(3, cycleAdj) ? "μ¬μ΄ν΄ μμ" : "DAG") << endl;
379
380 // 4. λͺ¨λ μμ μ λ ¬
381 cout << "\n[4] λͺ¨λ μμ μ λ ¬ μμ" << endl;
382 vector<vector<int>> smallAdj(4);
383 smallAdj[0] = {1, 2};
384 smallAdj[1] = {3};
385 smallAdj[2] = {3};
386 auto allSorts = findAllTopologicalSorts(4, smallAdj);
387 cout << " κ·Έλν: 0β1β3, 0β2β3" << endl;
388 cout << " κ°λ₯ν μμ: " << allSorts.size() << "κ°" << endl;
389 for (auto& order : allSorts) {
390 cout << " ";
391 printVector(order);
392 cout << endl;
393 }
394
395 // 5. κ³Όλͺ© μκ° μμ
396 cout << "\n[5] κ³Όλͺ© μκ° μμ" << endl;
397 vector<pair<int, int>> prereqs = {{1, 0}, {2, 0}, {3, 1}, {3, 2}};
398 cout << " κ³Όλͺ© μ: 4, μ μκ³Όλͺ©: (1,0), (2,0), (3,1), (3,2)" << endl;
399 cout << " μκ° κ°λ₯: " << (canFinish(4, prereqs) ? "μ" : "μλμ€") << endl;
400 auto order = findOrder(4, prereqs);
401 cout << " μκ° μμ: ";
402 printVector(order);
403 cout << endl;
404
405 // 6. 볡μ‘λ μμ½
406 cout << "\n[6] 볡μ‘λ μμ½" << endl;
407 cout << " | μκ³ λ¦¬μ¦ | μκ°λ³΅μ‘λ | 곡κ°λ³΅μ‘λ |" << endl;
408 cout << " |----------------|------------|------------|" << endl;
409 cout << " | Kahn (BFS) | O(V + E) | O(V) |" << endl;
410 cout << " | DFS κΈ°λ° | O(V + E) | O(V) |" << endl;
411 cout << " | λͺ¨λ μμ | O(V! Γ V) | O(V) |" << endl;
412
413 cout << "\n============================================================" << endl;
414
415 return 0;
416}