【算法模板】数据结构:三分查找

算法竞赛中的三分(ternary search)是一种用于在单峰函数(unimodal function)上找到最大值或最小值的搜索算法。与二分搜索(binary search)类似,三分搜索在每次迭代中将搜索空间分成三个部分,但三分搜索用于连续区间而不是离散区间。

算法思想

三分搜索的基本思想是在给定的区间内通过选择两个点将区间分成三个部分,并根据函数值的比较逐步缩小搜索范围。它主要适用于单峰函数,即在某一范围内函数有一个唯一的最大值或最小值。

算法步骤

假设我们在区间 [l,r] 上寻找函数 f(x) 的最大值。三分搜索的步骤如下:

  1. 初始化:设定初始区间 [l,r]。
  2. 计算两个分点:在区间 [l,r] 上选择两个点 m1 和 m2,通常选择方法为: m1=l+(r−l)/3, m2=r−(r−l)/3
  3. 比较函数值:计算 f(m1)和 f(m2),并进行比较:
    • 如果 f(m1)<f(m2),说明最大值在区间 [m1,r]内,舍弃 [l,m1]。
    • 如果 f(m1)>f(m2),说明最大值在区间 [l,m2]内,舍弃 [m2,r]。
    • 如果 f(m1)=f(m2),则最大值在区间 [m1,m2]内,舍弃 [l,m1]和 [m2,r]。
  4. 更新区间:根据上述比较结果更新区间 [l,r]。
  5. 终止条件:重复步骤 2 至 4,直到区间长度小于某个预定的精度阈值 ϵ。

例题

P3382 三分

如题,给出一个 N 次函数,保证在范围 [l, r] 内存在一点 x,使得 [l, x] 上单调增,[x, r] 上单调减。试求出 x 的值。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const double EPS = 1e-7;

// 计算多项式在 x 处的值
double polynomial_value(const vector<double>& coefficients, double x) {
    double value = 0.0;
    for (const auto& coeff : coefficients) {
        value = value * x + coeff;
    }
    return value;
}

// 三分搜索寻找极大值点
double ternary_search(const vector<double>& coefficients, double left, double right) {
    while (right - left > EPS) {
        double m1 = left + (right - left) / 3;
        double m2 = right - (right - left) / 3;
        double f1 = polynomial_value(coefficients, m1);
        double f2 = polynomial_value(coefficients, m2);
        if (f1 < f2) {
            left = m1;
        } else {
            right = m2;
        }
    }
    return (left + right) / 2;
}

int main() {
    int N;
    double l, r;
    cin >> N >> l >> r;
    vector<double> coefficients(N + 1);
    for (int i = 0; i <= N; ++i) {
        cin >> coefficients[i];
    }
    double x = ternary_search(coefficients, l, r);
    cout << fixed << setprecision(6) << x << endl;
    return 0;
}

Problem - G2 - Codeforces

这道交互算法题目要求找出一个缺失的刻度值 ( x ) (满足 ( 2 < x < 999 ))。对长度为 ( y ) 的物体进行测量时,尺子会根据 ( y ) 和 ( x ) 的关系给出不同的测量结果:

  • 如果 ( y < x ),则尺子正确测量为 ( y )。
  • 如果 ( y >= x ),则尺子错误测量为 ( y + 1 )。

你可以通过查询形如 ? a b 的指令,测量 ( a * b ) 矩形的面积,返回的面积是根据秘密尺子的测量结果计算的。题目中说明,通过最多 7 次查询找到 ( x ) 的值,查询返回的面积会受到 ( x ) 的影响。

每个测试用例独立,输入的第一行是测试用例的数量 ( t )( ( 1 <= t <= 1000 ))。正确输出找到的 ( x ) 值格式为 ! x,输出错误或超过查询次数将导致程序失败。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int query(int a, int b){
    cout << "? " << a << " " << b << endl;
    int res;   
    cin >> res;
    return res;
}

int main(){
    int task;
    cin >> task;
    while (task--){
        int l = 1, r = 999;
        while (l + 1 < r){
            int midl = l + (r - l) / 3;
            int midr = l + (r - l) * 2 / 3;
            int res = query(midl, midr);
            if (res == midl * midr){
                l = midr;
            }
            else if (res == midl * (midr + 1)){
                l = midl;
                r = midr;
            }
            else{
                // assert(res != (midl + 1) * (midr + 1));
                r = midl;
            }
        }
        cout << "! " << r << endl;
    }
    return 0;
}
相关推荐
晨曦夜月24 分钟前
笔试强训day5
数据结构·算法
H_z___25 分钟前
Hz的计数问题总结
数据结构·算法
她说彩礼65万27 分钟前
C# 反射
java·算法·c#
练习时长一年27 分钟前
LeetCode热题100(搜索插入位置)
数据结构·算法·leetcode
hz_zhangrl28 分钟前
CCF-GESP 等级考试 2025年9月认证C++六级真题解析
c++·算法·青少年编程·程序设计·gesp·2025年9月gesp·gesp c++六级
喇一渡渡39 分钟前
Java力扣---滑动窗口(1)
java·算法·排序算法
net3m331 小时前
雅特力单片机用串口USART_INT_TDE中断比用USART_INT_TRAC的 发送效率要高
java·开发语言·算法
@我漫长的孤独流浪1 小时前
程序综合实践第十二周-二叉树
算法·深度优先·图论
啊阿狸不会拉杆1 小时前
《数字图像处理》第 3 章 - 灰度变换与空间滤波
图像处理·人工智能·算法·计算机视觉·数字图像处理