Skip to content

Commit

Permalink
style: format documents
Browse files Browse the repository at this point in the history
  • Loading branch information
kimminss0 committed Nov 5, 2024
1 parent b672a1a commit deddc9c
Show file tree
Hide file tree
Showing 11 changed files with 206 additions and 188 deletions.
20 changes: 12 additions & 8 deletions posts/001-minimum-spanning-tree.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ published: 2024-09-13T17:00:00+09:00
katex: on
---

> PS(Problem Solving) 문제 풀이를 위해 작성한 글입니다. 이론적인 설명은 배제했습니다.
> PS(Problem Solving) 문제 풀이를 위해 작성한 글입니다. 이론적인 설명은
> 배제했습니다.
## 개요

최소신장트리(MST, Minimum spanning tree)는 그래프의 **모든 정점을 포함하는 subgraph 중 weight의 합이 최소인 트리**이다. 즉, MST는 그래프의 모든 정점을 최소비용으로 연결하는 트리다.

최소신장트리(MST, Minimum spanning tree)는 그래프의 **모든 정점을 포함하는
subgraph 중 weight의 합이 최소인 트리**이다. 즉, MST는 그래프의 모든 정점을
최소비용으로 연결하는 트리다.

## 전제

Expand All @@ -18,7 +20,9 @@ katex: on
- Connected graph에서 논한다.
- 간선 가중치가 **음수, 0**일 수 있다.

추가로, MST의 유일성을 보장하기 위해 간선 가중치가 모두 달라야 한다는 조건을 추가할 수 있다. 간선 가중치가 모두 다른 값을 가지면 MST가 유일하고, 그 역도 성립한다. 즉, 가중치가 같은 간선들이 있으면 MST를 여러 개 가질 수 있다.
추가로, MST의 유일성을 보장하기 위해 간선 가중치가 모두 달라야 한다는 조건을
추가할 수 있다. 간선 가중치가 모두 다른 값을 가지면 MST가 유일하고, 그 역도
성립한다. 즉, 가중치가 같은 간선들이 있으면 MST를 여러 개 가질 수 있다.

## 알고리즘

Expand All @@ -29,10 +33,10 @@ katex: on

각 알고리즘을 비교하면 다음과 같다.

|알고리즘|사용 환경|시간 복잡도|
|--------|---------|-----------|
|Kruskal|희소 그래프|$\text{O}(|E|\log{|E|})$|
|Prim|밀집 그래프|$\text{O}(|E|\log{|V|})$[^1]|
| 알고리즘 | 사용 환경 | 시간 복잡도 |
|----------|-------------|----------------------------|
| Kruskal | 희소 그래프 |$\text{O}(|E|\log{|E|})$ |
| Prim | 밀집 그래프 |$\text{O}(|E|\log{|V|})$[^1]|

[^1]: binary heap으로 구현 시

Expand Down
23 changes: 11 additions & 12 deletions posts/002-union-find.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,17 @@ Union-find의 주요 개념은 다음과 같다.

Union-find API는 다음 연산을 지원한다.

- `makeset(x)`: x를 유일한 원소로 두는 새로운 집합 생성. 자료구조에 새로운 원소를 추가할 때 사용한다.
- `makeset(x)`: x를 유일한 원소로 두는 새로운 집합 생성. 자료구조에 새로운
원소를 추가할 때 사용한다.
- `find(x)`: x가 속한 집합을 반환
- `union(x, y)`: x, y가 속한 두 집합을 병합
- `union(x, y)`: x, y가 속한 두 집합을 병합

Union-find는 **집합을 트리 형태로 구현**한다. `union`은 트리를 합치는 연산이고,
`find`는 트리의 root를 찾는 연산이다. 일반적으로 다음과 같이 구현한다.

- `find(x)`는 root에 도달할 때까지 parent를 타고 올라간다.
- `union(x, y)`는 두 트리의 root를 찾아 어느 하나를 다른 하나의 자식으로 편입한다.
- `union(x, y)`는 두 트리의 root를 찾아 어느 하나를 다른 하나의 자식으로
편입한다.

## 최적화 기법

Expand All @@ -52,19 +54,18 @@ Union-find는 **집합을 트리 형태로 구현**한다. `union`은 트리를

- 새로 초기화된 node의 rank는 0이다.
- root가 u, v인 두 트리를 병합할 때 다음을 따른다.
- u, v의 rank가 다르면 작은 것을 큰 것의 자식으로 편입한다.
- u, v의 rank가 같으면 어느 하나를 부모로 만들고 rank를 1 더한다.
- u, v의 rank가 다르면 작은 것을 큰 것의 자식으로 편입한다.
- u, v의 rank가 같으면 어느 하나를 부모로 만들고 rank를 1 더한다.
- height와 달리 rank가 업데이트되지 않는 경우:
- root가 아닌 node는 rank를 업데이트하지 않는다.
- [Path compression](#path-compression) 과정에서 height가 변해도 rank를
- root가 아닌 node는 rank를 업데이트하지 않는다.
- [Path compression](#path-compression) 과정에서 height가 변해도 rank를
업데이트하지 않는다.


### 경로 압축(Path compression)

`find` 연산 과정에서 트리를 평탄화(flatten)하는 작업을 같이 수행한다. `find(x)`
호출 시, x와 그 조상들을 한 번에 root로 직접 연결한다. 알고리즘의 설명은
후술한다.
후술한다.

## 의사코드

Expand All @@ -88,7 +89,6 @@ function union(x, y)
root_x.parent := root_y
if root_x.rank == root_y.rank
root_y.rank := root_y.rank + 1
```

다음은 `find(x)`의 의사코드다. Path compression을 적용하지 않았다.
Expand Down Expand Up @@ -119,7 +119,7 @@ function find(x)
root := x
while root.parent ≠ root
root := root.parent
while x.parent ≠ root
parent := x.parent
x.parent := root
Expand Down Expand Up @@ -158,7 +158,6 @@ Path splitting은 경로상 모든 부모 노드를 조부모로 연결한다. P
공격적으로 경로를 압축하나, 구현이 아주 조금 더 복잡하고 성능 차이는 거의 없다.
따라서 path halving 또한 선호된다.


## 참조

- [Wikipedia - Disjoint-set data structure](https://en.wikipedia.org/wiki/Disjoint-set_data_structure)
Expand Down
90 changes: 35 additions & 55 deletions posts/003-kruskal-algorithm.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,61 @@ title: Kruskal 알고리즘
published: 2024-09-18T17:00:00+09:00
---

> PS(Problem Solving) 문제 풀이를 위해 작성한 글입니다. 이론적인 설명은 배제했습니다.
> PS(Problem Solving) 문제 풀이를 위해 작성한 글입니다. 이론적인 설명은
> 배제했습니다.
## 개요

Kruskal 알고리즘은 [minimum spanning tree](/posts/1/minimum-spanning-tree)를 찾는 그리디 알고리즘이다. 간선을 정렬하여 최소 비용 간선부터 선택하며, 이 과정에서 사이클이 형성되지 않도록 한다. 사이클의 형성 여부를 판별하기 위해 Union-find 자료구조를 사용한다.

Kruskal 알고리즘은 [minimum spanning tree](/posts/1/minimum-spanning-tree)
찾는 그리디 알고리즘이다. 간선을 정렬하여 최소 비용 간선부터 선택하며, 이
과정에서 사이클이 형성되지 않도록 한다. 사이클의 형성 여부를 판별하기 위해
Union-find 자료구조를 사용한다.

## 알고리즘

알고리즘의 핵심은 매 순간 **최소 비용 간선을 선택**하면서, **사이클이 형성되지 않도록** 주의하는 것이다.
알고리즘의 핵심은 매 순간 **최소 비용 간선을 선택**하면서, **사이클이 형성되지
않도록** 주의하는 것이다.

매번 최소 비용 간선을 고른다는 점에서 알고리즘이 그리디(greedy)함을 알 수 있다. 이런 접근이 가능한 이유는 그래프 이론의 cut property에서 기인한다. 증명 과정은 생략하겠다.
매번 최소 비용 간선을 고른다는 점에서 알고리즘이 그리디(greedy)함을 알 수 있다.
이런 접근이 가능한 이유는 그래프 이론의 cut property에서 기인한다. 증명 과정은
생략하겠다.

사이클을 피하려면 같은 컴포넌트에 속하는 정점 사이에는 간선을 추가하면 안 된다. 다른 표현으로는, 두 정점 간의 연결성(connectivity)[^1]를 검사하여 연결되지 않은 경우(disconnected)에만 간선을 추가할 수 있다. 이와 같은 연결성 문제를 효율적으로 다루기 위해 **union-find** 자료구조를 사용한다.
사이클을 피하려면 같은 컴포넌트에 속하는 정점 사이에는 간선을 추가하면 안 된다.
다른 표현으로는, 두 정점 간의 연결성(connectivity)[^1]를 검사하여 연결되지 않은
경우(disconnected)에만 간선을 추가할 수 있다. 이와 같은 연결성 문제를
효율적으로 다루기 위해 **union-find** 자료구조를 사용한다.

위 내용을 정리하면 다음과 같다.

- 간선을 정렬하여 가중치가 작은 간선부터 선택한다.
- 해당 간선을 추가할 때 사이클이 형성되는지 확인한다. 사이클 형성 여부를 확인하기 위해 union-find 자료구조를 사용한다.

- 해당 간선을 추가할 때 사이클이 형성되는지 확인한다. 사이클 형성 여부를
확인하기 위해 union-find 자료구조를 사용한다.

[^1]: 무방향 그래프에서 두 정점 v와 u 사이에 경로가 존재하면, 이들을 **연결되었다(connected)**고 정의한다. 반대로, 경로가 존재하지 않으면 **연결되지 않았다(disconnected)**고 정의한다.
[^1]:
무방향 그래프에서 두 정점 v와 u 사이에 경로가 존재하면, 이들을
**연결되었다(connected)**고 정의한다. 반대로, 경로가 존재하지 않으면
**연결되지 않았다(disconnected)**고 정의한다.

## 자료구조

### Union-find

[Union-find](/posts/2/union-find)는 disjoint set[^2]의 collection을 나타내는 자료구조다. 다음 3가지 연산을 지원한다.
[Union-find](/posts/2/union-find)는 disjoint set[^2]의 collection을 나타내는
자료구조다. 다음 3가지 연산을 지원한다.

- `makeset(x)`: x를 유일한 원소로 두는 새로운 집합 생성. 초기화를 위해 사용.
- `find(x)`: x가 속한 집합을 반환
- `union(x, y)`: x, y가 속한 두 집합을 병합
- `union(x, y)`: x, y가 속한 두 집합을 병합

그래프의 각 컴포넌트는 하나의 disjoint set으로 볼 수 있다. 두 정점이 서로 다른 컴포넌트에 있는지 확인할 때는 `find` 연산을 사용하고, 간선 {u, v}[^3]를 선택한 이후 두 컴포넌트를 병합하기 위해 `union(u, v)` 연산을 사용할 수 있다.
그래프의 각 컴포넌트는 하나의 disjoint set으로 볼 수 있다. 두 정점이 서로 다른
컴포넌트에 있는지 확인할 때는 `find` 연산을 사용하고, 간선 {u, v}[^3]를 선택한
이후 두 컴포넌트를 병합하기 위해 `union(u, v)` 연산을 사용할 수 있다.

> **Note.** Union-find 자료구조는 그래프를 완전히 표현하지 않는다. 정점과 컴포넌트의 소속 관계만 다룰 뿐, 간선 정보는 직접적으로 관리하지 않는다.
> **Note.** Union-find 자료구조는 그래프를 완전히 표현하지 않는다. 정점과
> 컴포넌트의 소속 관계만 다룰 뿐, 간선 정보는 직접적으로 관리하지 않는다.
[^2]: 서로소 집합. 공통 원소가 없는 두 집합을 말한다.

[^3]: u, v를 양 끝 정점으로 하는 간선

## 의사코드
Expand All @@ -48,8 +66,9 @@ Kruskal 알고리즘은 [minimum spanning tree](/posts/1/minimum-spanning-tree)

- 그래프의 모든 컴포넌트가 하나의 정점만을 가지도록 초기화한다.
- 가중치가 작은 간선부터 순회한다.
- 양 끝 정점이 서로 연결되어있는지 확인한다.
- 연결되지 않았으면, 두 정점이 속하는 컴포넌트를 병합하고 간선은 저장해둔다.
- 양 끝 정점이 서로 연결되어있는지 확인한다.
- 연결되지 않았으면, 두 정점이 속하는 컴포넌트를 병합하고 간선은
저장해둔다.
- 간선을 모두 방문한 이후, 저장해둔 간선들은 MST를 이룬다.

다음은 알고리즘의 의사코드다.
Expand All @@ -74,47 +93,8 @@ function Kruskal(G = (V, E))
## 구현

> 구현은 BOJ 문제 답안을 참고한다.
- [\[BOJ\] #1197 최소 스패닝 트리](/posts/5/boj-1197#kruskal)
<!--다음은 c++17로 작성한 Kruskal 알고리즘이다.-->
<!---->
<!--```c++-->
<!--#include <tuple>-->
<!--#include <vector>-->
<!---->
<!--using namespace std;-->
<!---->
<!--class UnionFind {-->
<!--private:-->
<!-- // ...-->
<!---->
<!--public:-->
<!-- UnionFind(int num_vertices);-->
<!-- int find(int vertex);-->
<!-- bool unite(int vertex1, int vertex2); // union-->
<!--};-->
<!---->
<!--/***************************************************************/-->
<!---->
<!--using edge_t = tuple<int, int, int>; // weight, vertex1, vertex2-->
<!---->
<!--vector<edge_t> kruskal(int numVertices, vector<edge_t> &edges) {-->
<!-- UnionFind uf{numVertices};-->
<!---->
<!-- // compare by weight, ascending-->
<!-- auto comp = [](const edge_t &a, const edge_t &b) { return get<0>(a) < get<0>(b); };-->
<!-- sort(edges.begin(), edges.end(), comp);-->
<!---->
<!-- vector<edge_t> mstEdges;-->
<!-- for (auto [w, v, u] : edges) {-->
<!-- if (uf.unite(v, u)) {-->
<!-- mstEdges.push_back({w, v, u});-->
<!-- }-->
<!-- }-->
<!-- return mstEdges;-->
<!--}-->
<!--```-->
- [\[BOJ\] #1197 최소 스패닝 트리](/posts/5/boj-1197#kruskal)

## 기타

Expand Down
Loading

0 comments on commit deddc9c

Please sign in to comment.