Skip to content

Commit 054bd82

Browse files
committed
docs: 삼분 탐색 알고리즘 문서 업데이트
1 parent 72bc3ec commit 054bd82

File tree

2 files changed

+163
-13
lines changed

2 files changed

+163
-13
lines changed
Lines changed: 163 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
2-
title: Ternary Search
3-
description: Ternary Search 알고리즘에 대해 설명하는 페이지입니다.
2+
title: 삼분 탐색 (Ternary Search) 알고리즘
3+
description: 삼분 탐색 (Ternary Search) 알고리즘에 대해 정리한 페이지입니다.
44
date: 2024-02-23 00:00:00 +/-TTTT
55
categories: [Algorithms]
66
tags: [algorithm]
@@ -12,19 +12,169 @@ image:
1212
comments: true
1313
---
1414

15-
<blockquote class="prompt-info"><p><strong><u>Tags</u></strong> <br />
15+
<blockquote class="prompt-info"><p><strong><u>Tags</u></strong><br />
1616
Algorithm</p></blockquote>
1717

18-
## Introduction
18+
## 개요
1919

20-
- **Definition**
21-
- **삼분 탐색(Ternary search)****이분법**이 매 반복마다 답의 후보 구간을 절반으로 잘라 각 위치에서 함수의 값을 계산하는 것과 비슷하게, **답의 후보 구간을 삼등분하는 두 위치에서 함수의 값을 계산하는 탐색 방식이다.**
22-
- 삼분 탐색은 **볼록 함수(Convex function) 또는 오목 함수(Concave function)** 에서 **극값, 또는 최대/최소 값**을 찾을 때 유용하게 사용되는 기법이다.
23-
- 삼분 탐색은 한 번 반복할 때마다 **후보 구간의 크기를 2/3**로 줄여나간다.
24-
- 그래프를 갖는 함수의 최대점을 찾는 문제는 여러 가지 방법으로 풀 수 있다. 함수를 **직접 미분**하거나, **국소 탐색 알고리즘** 등으로 해결할 수 있다. 그러나 **삼분 탐색은 미분할 수 없는 함수에도 사용할 수 있으며, 국소 탐색에 비해 훨씬 빠르게 동작하고 수렴 판정이 용이**하기 때문에 더 자주 사용된다.
25-
> **국소 탐색(Local search)** 은 임의의 답을 하나 만들어 놓고 이 값을 조금씩 갱신하면서 답이 더 좋아지는 쪽으로 움직이는 알고리즘이다.
20+
`삼분 탐색(Ternary Search)` 알고리즘에 대해 정리한 페이지입니다.
2621

27-
## Examples
22+
## 삼분 탐색 (Ternary Search) 알고리즘
2823

29-
- <a href="https://github.com/HyunJinNo/Algorithm/blob/main/Ternary%20search/FOSSIL.java" target="_blank">FOSSIL</a>
30-
- <a href="https://github.com/HyunJinNo/Algorithm/tree/main/%EB%B0%B1%EC%A4%80/Gold/11664.%E2%80%85%EC%84%A0%EB%B6%84%EA%B3%BC%E2%80%85%EC%A0%90" target="_blank">11664. 선분과 점</a>
24+
### 개념
25+
26+
`삼분 탐색(Ternary Search)` 알고리즘은 탐색 구간을 절반으로 나누는 이분 탐색과 유사하게, 탐색 구간을 두 부분이 아닌 <b>세 부분</b>으로 나누는 탐색 방식입니다. 주로 `볼록 함수(Convex function)` 또는 `오목 함수(Concave function)`에서 <b>극값 또는 최대/최소값</b>을 찾을 때 자주 사용됩니다.
27+
28+
<blockquote class="prompt-info"><p><strong><u>Info.</u></strong><br />
29+
<b>볼록 함수(Convex function)</b>: <b>아래로 볼록</b>하게 생긴 함수<br />
30+
<b>오목 함수(Concave function)</b>: <b>위로 볼록</b>하게 생긴 함수</p></blockquote>
31+
32+
### 특징
33+
34+
삼분 탐색 알고리즘의 특징은 다음과 같습니다.
35+
36+
- `단봉 함수(Unimodal function)`
37+
38+
삼분 탐색 알고리즘은 단봉 함수에서만 사용할 수 있습니다. 만약 함수의 기울기가 0인 구간이 존재하고 그 때의 함수값이 극값이 아니라면 삼분 탐색 알고리즘을 사용할 수 없습니다.
39+
40+
<blockquote class="prompt-info"><p><strong><u>Info.</u></strong><br />
41+
<b>단봉 함수(Unimodal function)</b>: 어떤 점까지 증가하다고 그 이후로 감소하거나, 반대로 감소하다가 증가하는 형태의 함수</p></blockquote>
42+
43+
- `3등분`
44+
45+
이분 탐색이 탐색 구간을 절반으로 나누고 하나의 중간점을 사용한다면, 삼분 탐색은 탐색 구간을 3등분하고 두 개의 중간점을 사용합니다.
46+
47+
- `정수와 실수`
48+
49+
정수 뿐만 아니라 실수 구간에서도 삼분 탐색 알고리즘을 사용할 수 있습니다. 특히 실수 구간에서는 `오차 허용값(ε)`을 기준으로 반복합니다.
50+
51+
- `시간 복잡도(Time Complexity)`
52+
53+
탐색 구간을 3등분하여 매번 구간 길이를 2/3로 줄이므로 `O(log₃N)`의 시간 복잡도를 갖습니다.
54+
55+
### 활용
56+
57+
삼분 탐색 알고리즘은 다음과 같은 분야에서 활용됩니다.
58+
59+
- `극값 찾기`
60+
61+
볼록 함수 또는 오목 함수에서 극값을 찾는데 활용됩니다.
62+
63+
- `최대/최소값 찾기`
64+
65+
2차 함수, 3차 함수의 최대/최소값을 찾는데 활용됩니다.
66+
67+
### 구현
68+
69+
삼분 탐색 알고리즘을 구현하기 위해선 먼저 탐색 구간을 파악해야 합니다. 탐색 구간이 [lo, hi]일 때, 탐색 구간을 3등분하기 위해 설정하는 두 개의 중간점의 위치는 각각 `(2 * lo + hi) / 3`, `(lo * 2 + hi) / 3`입니다.
70+
71+
예를 들어 `y = -0.5x² + 2x + 12`라는 2차 함수에서 탐색 구간이 [-3, 6]일 때의 최댓값을 찾는 문제가 있을 경우, 탐색 구간을 3등분하기 위해 설정하는 두 개의 중간점은 `x = (2 * (-3) + 6) / 3 = 0`, `x = (-3 + 2 * 6) / 3 = 3`입니다.
72+
73+
<img src="/assets/img/algorithms/ternary-search/pic1.avif" alt="y = -0.5x² + 2x + 12" />
74+
75+
위의 사진을 보면 알 수 있듯이 `x = 0`인 지점보다 `x = 3`인 지점의 함수값이 더 큰 것을 알 수 있습니다. 이를 통해 최댓값은 왼쪽 1/3 구간 [-3, 0]에는 없다는 점을 알 수 있습니다. 만약 구간 [-3, 0]에 최댓값이 있다면 왼쪽 중간점의 함수값이 오른쪽 중간점의 함수값보다 커야하기 때문입니다. 따라서 왼쪽 1/3 구간을 배제하고 나머지 2/3 구간을 탐색하는 식으로 진행됩니다.
76+
77+
이 예시를 자바스크립트 코드로 나타내면 다음과 같습니다.
78+
79+
<blockquote class="prompt-info"><p><strong><u>Info.</u></strong><br />
80+
삼분 탐색을 실수 구간에서 사용할 때, 실수는 무한히 많은 값을 가지기 때문에 left와 right 사이를 완전히 좁혀서 한 점으로 만드는 것을 불가능합니다. 따라서 무한 루프를 방지하기 위해 보통 충분히 작아진 구간에서 멈출 수 있도록 <b>오차 허용값(ε)</b>을 사용합니다.</p></blockquote>
81+
82+
```javascript
83+
const func = (x) => {
84+
return -0.5 * x * x + 2 * x + 12;
85+
};
86+
87+
let left = -3;
88+
let right = 6;
89+
const eps = 1e-6; // 오차 허용값: 0.000001
90+
91+
while (right - left > eps) {
92+
const a = (2 * left + right) / 3;
93+
const b = (left + 2 * right) / 3;
94+
95+
if (func(a) > func(b)) {
96+
right = b;
97+
} else {
98+
left = a;
99+
}
100+
}
101+
102+
console.log(left); // 1.9999996102999702
103+
console.log(func(left)); // 13.999999999999924
104+
```
105+
106+
## Example
107+
108+
- <a href="https://www.acmicpc.net/problem/11664" target="_blank">11664번: 선분과 점</a>
109+
110+
```typescript
111+
const path: string =
112+
process.platform === "linux" ? "/dev/stdin" : "./TypeScript/src/input.txt";
113+
const input: readonly number[] = require("fs")
114+
.readFileSync(path)
115+
.toString()
116+
.split(" ")
117+
.map(Number);
118+
119+
class Point {
120+
public readonly x: number;
121+
public readonly y: number;
122+
public readonly z: number;
123+
124+
constructor(x: number, y: number, z: number) {
125+
this.x = x;
126+
this.y = y;
127+
this.z = z;
128+
}
129+
}
130+
131+
const A = new Point(input[0], input[1], input[2]);
132+
const B = new Point(input[3], input[4], input[5]);
133+
const C = new Point(input[6], input[7], input[8]);
134+
135+
/**
136+
* 두 점 사이의 거리를 반환하는 함수
137+
* @param point 선분 위의 점
138+
* @param C 점 C
139+
* @returns 두 점 사이의 거리
140+
*/
141+
const getDistance = (point: Point, C: Point): number => {
142+
return Math.sqrt(
143+
(point.x - C.x) ** 2 + (point.y - C.y) ** 2 + (point.z - C.z) ** 2
144+
);
145+
};
146+
147+
const solve = (): number => {
148+
let lo = new Point(A.x, A.y, A.z);
149+
let hi = new Point(B.x, B.y, B.z);
150+
151+
for (let iter = 0; iter < 100; iter++) {
152+
const a = new Point(
153+
(lo.x * 2 + hi.x) / 3,
154+
(lo.y * 2 + hi.y) / 3,
155+
(lo.z * 2 + hi.z) / 3
156+
);
157+
const b = new Point(
158+
(lo.x + hi.x * 2) / 3,
159+
(lo.y + hi.y * 2) / 3,
160+
(lo.z + hi.z * 2) / 3
161+
);
162+
163+
if (getDistance(a, C) > getDistance(b, C)) {
164+
lo = a;
165+
} else {
166+
hi = b;
167+
}
168+
}
169+
170+
return getDistance(lo, C);
171+
};
172+
173+
console.log(solve());
174+
```
175+
176+
## 참고 자료
177+
178+
- <a href="https://www.yes24.com/product/goods/8006522" target="_blank">알고리즘 문제 해결 전략 세트 | 구종만 | 인사이트(insight) - 예스24</a>
179+
- <a href="https://00ad-8e71-00ff-055d.tistory.com/41" target="_blank">39. Ternary Search</a>
180+
- <a href="https://namu.wiki/w/볼록함수" target="_blank">볼록함수 - 나무위키</a>
10.8 KB
Binary file not shown.

0 commit comments

Comments
 (0)