Skip to content

Commit b09cafe

Browse files
committed
feat: 위상정렬 내용 업로드 및 li 태그의 폰트 및 margin, padding 수정
1 parent eab5188 commit b09cafe

File tree

3 files changed

+162
-2
lines changed

3 files changed

+162
-2
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
---
2+
title: "위상정렬(Topological Sort)"
3+
date: 2025-09-01
4+
# toc: true
5+
categories:
6+
- algorithm
7+
tags:
8+
- algo
9+
- math
10+
---
11+
12+
위상 정렬(Topological Sort)은 방향성 비순환 그래프(Directed Acyclic Graph, DAG)에 대해 정점들을 정렬하는 알고리즘입니다.
13+
14+
<br>
15+
16+
DAG는 모든 정점에서 시작하여 다른 정점으로 이동할 수 있지만, 어떤 정점에서 시작해서 다른 정점으로 이동할 때 순환이 발생하지 않는 그래프를 의미합니다.
17+
18+
<br>
19+
20+
**위상 정렬의 핵심**
21+
22+
DAG의 정점들을 순서대로 나열했을 때, 모든 간선이 왼쪽 정점에서 오른쪽 정점으로 향하도록 하는 순서입니다. 즉, 각 정점 u에 대해, u에서 v로 가는 간선이 있다면, u는 v보다 먼저 정렬되어야 합니다.(의존성에 맞게 정렬)
23+
24+
25+
26+
<br>
27+
28+
**시간 복잡도**
29+
30+
위상 정렬 알고리즘의 시간 복잡도는 사용되는 구현 방식에 따라 달라진다.
31+
32+
33+
| 알고리즘 | 구현 방식 | 시간 복잡도 | 공간 복잡도 | 장점 | 단점 |
34+
|---|---|---|---|---|---|
35+
| **칸 알고리즘 (Kahn's Algorithm)** | BFS (너비 우선 탐색) | O(V + E) | O(V) | 구현 용이, 효율적, 사이클 확인 가능 | 메모리 사용량 증가 가능성 |
36+
| **DFS (Recursive)** | 재귀적인 DFS | O(V + E) | O(V) | 직관적, 메모리 효율적 | 스택 오버플로우 가능성, 구현 복잡 |
37+
| **DFS (Iterative)** | 반복문 + 스택 | O(V + E) | O(V) | 스택 오버플로우 방지, 안전 | 구현 복잡 |
38+
39+
40+
일반적으로 시간복잡도, 공간 복잡도에는 큰 차이가 없지만, DFS로 구현하는 경우 오버플로우 및 단점이 있어 Kahn's Algorithm 을 많이 사용됩니다.
41+
42+
<br>
43+
44+
위에서 설명한 Kahn's Algorithm의 시간 복잡도는...
45+
46+
- 진입 차수 계산: 그래프의 모든 정점과 간선을 순회해야 하므로 O(V + E) 시간이 소요됩니다.
47+
48+
- 큐 초기화: 진입 차수가 0인 정점을 찾는 데 O(V) 시간이 소요됩니다.
49+
50+
- BFS 반복: 큐의 크기는 최대 V가 될 수 있으며, 각 정점은 한 번씩 큐에서 꺼내어 처리됩니다. 따라서 BFS 반복에는 O(V + E) 시간이 소요됩니다.
51+
52+
따라서 전체적인 시간 복잡도는 O(V + E) + O(V) + O(V + E) = O(V + E) 가 됩니다. 이는 그래프의 정점 수와 간선 수에 비례하는 시간 복잡도이므로, 큰 그래프에서도 효율적으로 위상 정렬을 수행할 수 있습니다.
53+
54+
55+
<br>
56+
57+
### 코드 예시 (Kahn's Algorithm)
58+
59+
- [BOJ 1516](https://www.acmicpc.net/problem/1516)
60+
61+
```java
62+
import java.util.*;
63+
64+
import java.util.*;
65+
import java.io.*;
66+
67+
public class Main {
68+
69+
70+
public static void main(String[] args) throws IOException {
71+
BufferedReader br =new BufferedReader(new InputStreamReader(System.in));
72+
73+
int N = Integer.parseInt(br.readLine());
74+
ArrayList<ArrayList<Integer>> graph = new ArrayList<>();
75+
int[] indegree = new int[N+1];
76+
int[] times = new int[N+1];
77+
int[] result = new int[N+1];
78+
79+
for (int i=0; i<=N; i++) {
80+
graph.add(new ArrayList<Integer>()); // 그래프를 그린다.
81+
}
82+
83+
StringTokenizer st;
84+
for(int i=1; i<=N; i++) {
85+
st = new StringTokenizer(br.readLine());
86+
times[i] = Integer.parseInt(st.nextToken());
87+
while(true) {
88+
int num = Integer.parseInt(st.nextToken());
89+
if (num == -1) {break;}
90+
graph.get(num).add(i);
91+
indegree[i]++; // 진입차수로 그래프에 연결된 만큼 증가한다.
92+
}
93+
}
94+
95+
Queue<Integer> que = new LinkedList<Integer>();
96+
97+
for(int i=1; i<=N; i++) {
98+
if (indegree[i] == 0) { // 진입차수가 0인 것 부터 탐색한다.
99+
que.add(i);
100+
}
101+
}
102+
103+
while (!que.isEmpty()) {
104+
int now = que.poll();
105+
106+
for (int j : graph.get(now)) { // 진입차수가 0인 것에서 최대 값을 찾기 위해 반복한다.
107+
result[j] = Math.max(result[j], (result[now] + times[now])); // 문제에 따라서 최소 시간을 계산하는 경우도 있다.
108+
indegree[j]--;
109+
if (indegree[j] == 0) {
110+
que.add(j);
111+
}
112+
}
113+
}
114+
115+
for(int i=1 ; i<=N; i++) {
116+
System.out.println(result[i] + times[i]);
117+
}
118+
119+
}
120+
121+
}
122+
123+
```
124+
125+
### 코드 설명
126+
127+
inDegree : 각 정점의 진입 차수를 저장하는 배열입니다.
128+
129+
- 큐 초기화 : 진입 차수가 0인 정점들을 큐에 넣습니다.
130+
- BFS 반복 : 큐가 빌 때까지 반복하며, 큐에서 정점을 꺼내 결과 리스트에 추가하고, 해당 정점의 이웃 정점들의 진입 차수를 감소시킵니다.
131+
- 결과 : 여기서 문제에 따라서 어떤 위상정렬에서 최소 시간을 구하는 문제도 있을 수 있고, 단순히 순서를 나열하는 문제에 따라 result 배열을 업데이트하는 방식이 달라진다.
132+
133+
<br>
134+
135+
만약 사이클을 검사해야한다면...
136+
사이클 검사: 위상정렬로 인한 나열된 결과 리스트의 크기가 정점 수와 다르면 사이클이 존재함을 의미한다.
137+
138+
<br>
139+
140+
**추천 문제**
141+
142+
작업 간의 의존성을 고려하여 작업을 순서대로 나열하거나.. 여러가지의 답 중 가장 최소길이의 답을 출력하거나..
143+
여러 답안의 개수를 세거나 등이 포함된다.
144+
145+
문제로는 [1005 : ACM Craft](https://www.acmicpc.net/problem/1005), [2056: 작업](https://www.acmicpc.net/problem/2056)을 추천한다.
146+
147+
<br>
148+
149+
150+

_sass/minimal-mistakes/_page.scss

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,16 @@ body {
151151
}
152152
}
153153

154+
/* posts (single layout): remove default left padding on unordered lists */
155+
.layout--single & ul {
156+
padding-left: 1rem;
157+
margin-left: 0.5rem;
158+
159+
> li > p {
160+
font-size: 0.7rem;
161+
}
162+
}
163+
154164
dt {
155165
margin-top: 1em;
156166
font-family: $sans-serif;

_sass/minimal-mistakes/_syntax.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ figure.highlight {
1313
border-radius: $border-radius;
1414
margin-top: 5%;
1515
margin-bottom: 5%;
16-
margin-right: 5%;
17-
margin-left: 5%;
16+
// margin-right: 5%;
17+
// margin-left: 5%;
1818

1919
> pre,
2020
pre.highlight {

0 commit comments

Comments
 (0)