삼분 탐색 (Ternary Search)
정의
삼분 탐색 (Ternary Search) 은 단봉 (unimodal) 함수의 극값 (최대 / 최소) 을 O(log N) 에 찾는 알고리즘. 구간을 3등분하는 두 점 m1, m2 에서 함수값을 비교, 극값이 없는 1/3 을 매번 제거한다.
단봉: 최대점이 하나이고, 그 전까지 증가, 그 후 감소 (또는 반대). Binary Search 이 배열에서 값을 찾는다면, 삼분 탐색은 함수 그래프에서 극값 위치를 찾는다.
문제 상황과 동기
함수 f(x) 의 극값 위치를 알고 싶다 (f(x) 미분 불가 또는 비용 높음).
- naive: 모든 x 를 시도. O(N) 또는 무한 (실수 구간).
- 삼분 탐색: 단봉이면 구간 1/3 씩 제거. O(log N).
예: f(x) = -(x-5)^2 + 10 의 최대값. 미분하면 x=5 지만, f 가 복잡하면 미분 어려움. 삼분 탐색은 함수값만 평가해서 극값을 찾는다.
핵심 통찰: “m1, m2 에서 f(m1) < f(m2) 이면, 극대는 [m1, hi] 에 있다”.
실무: 물리 시뮬레이션, 비용 함수 최적화, 게임 AI 파라미터 튜닝.
시각화
핵심 아이디어
invariant: 극값은 항상 [lo, hi] 구간 안에 있다. 매 단계에서 구간을 3등분: m1 = lo + (hi - lo) / 3, m2 = hi - (hi - lo) / 3.
초기: lo = 구간 시작, hi = 구간 끝
while hi - lo > eps:
m1 = lo + (hi - lo) / 3
m2 = hi - (hi - lo) / 3
if f(m1) < f(m2): # 최대 찾기
lo = m1 # 극대는 [m1, hi] 에
else:
hi = m2 # 극대는 [lo, m2] 에
return (lo + hi) / 2
최소 찾기는 조건 반대. 각 단계마다 구간 길이가 2/3 배.
알고리즘
최대값 찾기 (실수 구간)
ternary_max(lo, hi, f):
for _ in range(100): # log_{3/2}(구간) 회면 충분
m1 = lo + (hi - lo) / 3
m2 = hi - (hi - lo) / 3
if f(m1) < f(m2):
lo = m1
else:
hi = m2
return (lo + hi) / 2
최소값 찾기
ternary_min(lo, hi, f):
for _ in range(100):
m1 = lo + (hi - lo) / 3
m2 = hi - (hi - lo) / 3
if f(m1) > f(m2):
lo = m1
else:
hi = m2
return (lo + hi) / 2
정수 구간
ternary_max_int(lo, hi, f):
while hi - lo > 2:
m1 = lo + (hi - lo) / 3
m2 = hi - (hi - lo) / 3
if f(m1) < f(m2):
lo = m1
else:
hi = m2
return max(f(lo), f(lo+1), ..., f(hi)) 에서 argmax
구현
// f(x) = -(x-5)^2 + 10 의 최대값 위치
#include <bits/stdc++.h>
using namespace std;
double f(double x) {
return -(x - 5.0) * (x - 5.0) + 10.0;
}
int main() {
double lo, hi;
cin >> lo >> hi;
for (int i = 0; i < 100; i++) {
double m1 = lo + (hi - lo) / 3.0;
double m2 = hi - (hi - lo) / 3.0;
if (f(m1) < f(m2)) lo = m1;
else hi = m2;
}
double x = (lo + hi) / 2.0;
cout << fixed << setprecision(6) << x << " " << f(x) << "\n";
}0.0 10.05.000000 10.000000복잡도
| 항목 | 값 |
|---|---|
| 시간 | O(log_1.5 (hi - lo) × T_f), T_f = f(x) 계산 시간 |
| 공간 | O(1) |
| 전제 | f(x) 가 단봉 (unimodal) |
| 비교 횟수 | 약 log_{1.5}(hi - lo) (이분 탐색의 ~1.6 배) |
실수 구간 [0, 10^9] 에서도 100 회 반복이면 10^-15 정밀도.
변형 / 활용
| 형태 | 설명 |
|---|---|
| 포물선 최적화 | 2차 함수 f(x) = ax^2 + bx + c |
| 비선형 최적화 | 비용 함수, 손실 함수 (gradient 불필요) |
| 정수 구간 | 이산 f(i), 마지막에 남은 3개 직접 비교 |
| 다변수 극값 | x, y 각각 독립적으로 삼분 (Golden-section search) |
| 물리 시뮬레이션 | 발사각, 속도 최적화 |
함정
1. 단봉 가정 위반
f(x) 에 극값이 여러 개면 틀린 답. 예: sin(x) 는 단봉 아님.
2. f(m1) == f(m2) 처리
부동소수점 오차로 거의 같을 때 무한 루프 / 느림. eps 또는 고정 횟수 로 종료.
// 잘못: while (abs(hi - lo) > 1e-9) // 무한 가능
// 올바름: for (int i = 0; i < 100; i++)
3. 이분 탐색과 혼동
- 이분 탐색: 정렬된 배열에서 값 찾기, O(log N).
- 삼분 탐색: 단봉 함수에서 극값 찾기, O(log N).
목적이 다름.
4. 정수 구간 끝 처리
정수 삼분은 hi - lo <= 2 일 때 직접 확인.
while (hi - lo > 2) { ... }
// 남은 lo, lo+1, lo+2, hi 직접 비교
이분 탐색 vs 삼분 탐색
| 비교 | 이분 탐색 | 삼분 탐색 |
|---|---|---|
| 입력 | 정렬된 배열 | 단봉 함수 |
| 목표 | 값 찾기 | 극값 위치 |
| 비교 | 1 점 (mid) | 2 점 (m1, m2) |
| 수렴 | O(log N) | O(log_1.5 N) (약간 느림) |
| 응용 | 검색, parametric search | 최적화, 물리 |
BOJ 연습 문제
| 번호 | 제목 | 정답률 | 링크 |
|---|---|---|---|
| BOJ 11662 | 민호와 강호 | - | kokoa-lab |
| BOJ 8986 | 전봇대 | - | kokoa-lab |
| BOJ 2515 | 전시장 | - | kokoa-lab |
| BOJ 1418 | K-세준수 | - | kokoa-lab |
참고
- Binary Search
- Parametric Search
- Golden-section search (수학적 최적 분할 비율)
이 글의 용어 (3개)
- 매개 변수 탐색 (Parametric Search)algorithm
- 정의 매개 변수 탐색 (Parametric Search) 은 답 자체를 이분 탐색하는 기법. "조건을 만족하는 최소값 / 최대값" 문제에서, 조건 만족 여부가 단조성 (monot…
- 이분 탐색 (Binary Search)algorithm
- 정의 이분 탐색 (Binary Search) 은 정렬된 시퀀스에서 목표값의 위치를 O(log N) 에 찾는 알고리즘. 매 단계에서 후보 구간을 절반으로 줄인다. 탐색이 본질이 아…
- Golden-section Search: 단봉 함수 최적화algorithm
- 정의 단봉 (unimodal) 함수 위에서 최소/최대를 찾는 탐색. 이분 탐색을 단봉 함수용으로 확장. 삼분 탐색 (Ternary Search) 구간 [l, r] 을 세 등분하여…
💬 댓글