본문으로 건너뛰기
김신건의 로그

삼분 탐색 (Ternary Search)

· 수정 · 📖 약 2분 · 791자/단어 #algorithm #search #optimization #unimodal
ternary search, 삼분 탐색, 삼분검색, 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";
}
stdin
0.0 10.0
결과
5.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 1418K-세준수-kokoa-lab

참고

이 글의 용어 (3개)
매개 변수 탐색 (Parametric Search)algorithm
정의 매개 변수 탐색 (Parametric Search) 은 답 자체를 이분 탐색하는 기법. "조건을 만족하는 최소값 / 최대값" 문제에서, 조건 만족 여부가 단조성 (monot…
이분 탐색 (Binary Search)algorithm
정의 이분 탐색 (Binary Search) 은 정렬된 시퀀스에서 목표값의 위치를 O(log N) 에 찾는 알고리즘. 매 단계에서 후보 구간을 절반으로 줄인다. 탐색이 본질이 아…
Golden-section Search: 단봉 함수 최적화algorithm
정의 단봉 (unimodal) 함수 위에서 최소/최대를 찾는 탐색. 이분 탐색을 단봉 함수용으로 확장. 삼분 탐색 (Ternary Search) 구간 [l, r] 을 세 등분하여…

이 개념을 다룬 위키 페이지 (1)

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기