核心概述
三分搜索用于单峰(凸/凹或先增后减)的一维函数极值定位,每轮评估两内点并舍弃约 1/3 区间,可在连续域与整数域内以对数轮次收敛到极值。
原文引述
Description: Ternary search on unimodal f over an interval; evaluate at two interior points and shrink to the better side. Works for real (with eps) and integer (discrete) domains.(摘自本节点现有英文注释) Time: O(log((R-L)/ε)) for real; O(log N) for integer domain(摘自本节点现有英文注释) Status: tested(摘自本节点现有英文注释)
展开阐述
-
适用条件与目标
- 单峰性:存在唯一极大/极小点,且两侧单调。
- 域类型:连续/离散均可;连续域以精度 ε 收敛,整数域以小范围线性收尾。
- 目标:极大化或极小化(最小化可对 f 取相反数)。
-
核心流程
- 连续区间 [l, r]:
- 取 m1 = l + (r−l)/3, m2 = r − (r−l)/3。
- 若 f(m1) < f(m2),则极值在 [m1, r];否则在 [l, m2]。
- 迭代至 r−l < ε,返回中点或当前更优点。
- 整数区间 [l, r]:
- while r−l > 3:同上更新边界。
- 对收尾小段逐点枚举取最优。
- 连续区间 [l, r]:
-
代码框架(连续实数极大值)
// 目标函数应满足单峰性
double ternary_search_double(double l, double r, double eps = 1e-9) {
auto f = [](double x) { /* TODO: 定义 f(x) */ return -x*x + 3*x + 1; };
while (r - l > eps) {
double m1 = l + (r - l) / 3.0;
double m2 = r - (r - l) / 3.0;
if (f(m1) < f(m2)) l = m1; else r = m2;
}
return (l + r) / 2.0; // 近似极大点
}- 代码框架(整数域极大值)
// 在整数区间 [l, r] 上极大化 f(i)
long long ternary_search_int(long long l, long long r) {
auto f = [](long long x) { /* TODO: 定义 f(x) */ return -x*x + 3*x + 1; };
while (r - l > 3) {
long long m1 = l + (r - l) / 3;
long long m2 = r - (r - l) / 3;
if (f(m1) < f(m2)) l = m1; else r = m2;
}
long long bestx = l; auto bestv = f(l);
for (long long x = l + 1; x <= r; ++x) {
auto v = f(x);
if (v > bestv) bestv = v, bestx = x;
}
return bestx;
}-
复杂度与数值注意
- 每轮舍弃约 1/3 区间,评估次数为 O(log((R−L)/ε))(连续)或 O(log N)(整数)。
- 函数评估代价大时,可缓存 f(m1)/f(m2) 避免重复计算。
- 浮点误差:并不要求严格单峰也可工作,但 ε 的选择影响精度与轮次。
-
与黄金分割搜索的关系
- 黄金分割搜索在连续域同属单峰搜索范式,复用一个内点以减少一次函数评估;收敛速度同阶,常数上黄金分割更优,三分法更直观。
-
应用场景
- 一维参数调优(代价函数单峰)。
- 凸/凹函数的极值定位与阈值选择。
- 组合问题中的离散单峰结构最优点搜索。