三分法

三分法可以求出单峰函数(不一定是凸函数,可以是下面这样)的最大值(峰值),或者单谷函数的最小值(谷值)。
image
我们以单峰函数为例,在 [l,r](最小值所在范围)任取 llmidrmidr,求出 f(lmid)f(rmid)
image
如若有 f(lmid)>f(rmid),那么 rmidr 这一段区间一定是递减的,可以缩小范围到 (l,rmid)
在实数域上三分,精度为 eps 的话,考虑什么时候结束三分。如果 l=r2eps,这时刚好会出现无限循环,也就是 l 不断赋值为 l。那么我们考虑当 l>=r3eps 的时候结束。
例题:https://www.luogu.com.cn/problem/P3382

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define f(i, a, b) for(int i = (a); i <= (b); i++)
#define cl(i, n) i.clear(),i.resize(n);
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
const int inf = 1e9;
int n; 
ld eps = 1e-7;
ld a[15];
ld qpow(ld x, int k) {
    ld ans = 1;
    while(k) {
        if(k&1)ans=ans*x;
        x=x*x;
        k>>=1;
    }
    return ans;
}
ld fx(ld x) {
    ld ans = 0;
    f(i, 0, n) {
        ans += qpow(x, i) * a[i];
    }
    return ans;
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);
    //think twice,code once.
    //think once,debug forever.
    cin >> n;
    ld l, r; cin >> l >> r;
    for(int i = n; i >= 0; i--) cin >> a[i];
    while(l + 3 * eps < r) {
        ld mid = (l + r) / 2;
        ld lmid = mid - eps;
        ld rmid = mid + eps;
        if(fx(lmid) > fx(rmid)) r = rmid;
        else l = lmid;
    }
    cout << l << endl;
    return 0;
}

也可以写成 rmid,lmid,但是这样每次会掉 eps 的精度,那么我们的精度设小一点,0.01ϵ 差不多。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define f(i, a, b) for(int i = (a); i <= (b); i++)
#define cl(i, n) i.clear(),i.resize(n);
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
const int inf = 1e9;
int n; 
ld eps = 1e-7;
ld a[15];
ld qpow(ld x, int k) {
    ld ans = 1;
    while(k) {
        if(k&1)ans=ans*x;
        x=x*x;
        k>>=1;
    }
    return ans;
}
ld fx(ld x) {
    ld ans = 0;
    f(i, 0, n) {
        ans += qpow(x, i) * a[i];
    }
    return ans;
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);
    //think twice,code once.
    //think once,debug forever.
    cin >> n;
    ld l, r; cin >> l >> r;
    for(int i = n; i >= 0; i--) cin >> a[i];
    while(l + eps < r) {
        ld mid = (l + r) / 2;
        ld lmid = mid - eps;
        ld rmid = mid + eps;
        if(fx(lmid) > fx(rmid)) r = mid;
        else l = mid;
    }
    cout << l << endl;
    return 0;
}

还有种高级的优化:优选法,但是比较难记就算了。这样写谁都会,不折腾了。

posted @   OIer某罗  阅读(154)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示