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

算法竞赛中的三分(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;
}
相关推荐
tobias.b8 小时前
408真题解析-2010-7-数据结构-无向连通图
数据结构·算法·图论·计算机考研·408真题解析
良木生香9 小时前
【鼠鼠优选算法-双指针】003:快乐数 & 004:盛水最多的容器
算法
Cx330❀9 小时前
【优选算法必刷100题】第41-42题(模拟):Z 字形变换,外观数列
c++·算法
沃尔特。9 小时前
直流无刷电机FOC控制算法
c语言·stm32·嵌入式硬件·算法
CW32生态社区9 小时前
CW32L012的PID温度控制——算法基础
单片机·嵌入式硬件·算法·pid·cw32
Cx330❀9 小时前
【优选算法必刷100题】第038题(位运算):消失的两个数字
开发语言·c++·算法·leetcode·面试
漫随流水9 小时前
leetcode回溯算法(93.复原IP地址)
数据结构·算法·leetcode·回溯算法
燃于AC之乐9 小时前
我的算法修炼之路--5——专破“思维陷阱”,那些让你拍案叫绝的非常规秒解
c++·算法·贪心算法·bfs·二分答案·扩展域并查集·动态规划(最长上升子序列)
艾莉丝努力练剑9 小时前
【优选算法必刷100题】第021~22题(二分查找算法):山脉数组的峰顶索引、寻找峰值
数据结构·c++·算法·leetcode·stl
艾莉丝努力练剑9 小时前
【优选算法必刷100题】第007~008题(双指针算法):三数之和、四数之和问题求解
linux·算法·双指针·优选算法