洛谷 P3382 【模板】三分法

洛谷 P3382 【模板】三分法

传送门

思路

这是一道三分的模板题
用于求单峰函数的极值

首先,在函数上标4个点:\(x=l,r,mid,mmid\)。其中\(mmid\)\(mid\)\(r\)的中点。(其实就是把函数三等分了)

然后我们需要通过迭代来缩小范围(\(while\)循环)

如果\(f(mid)>f(mmid)\),则\(mmid\)一定在峰的右边。
如果\(f(mid),则\(mid\)一定在峰的左边。

证明:
1.我们假设存在\(f(mid)>f(mmid)\)\(mmid\)在峰的左边。
由于\(f(x)\)在峰的左边单调递增,且\(f(mid)>f(mmid)\),所以\(mid\)\(mmid\)的右边。
然而\(mmid = \frac{mid+rt}{2}\),显然\(mid\)\(mmid\)左边。矛盾。

2.我们假设存在\(f(mid)\(mid\)在峰的右边。
由于\(f(x)\)在峰的右边单调递减,且\(f(mid),所以\(mid\)\(mmid\)的右边。
然而\(mmid = \frac{mid+rt}{2}\),显然\(mid\)\(mmid\)左边。矛盾。

那么如何求\(f(n)\)

这就需要用到秦九韶公式了,大家可以自行百度,这里就不说了

让我帮帮你吧

代码

#include
#define db double
#define N 20
using namespace std;

const db eps=1e-6;
int n;
db a[20],l,r,mid,mmid,k;

db f(db x){
    db s=0;
    for(int i=0;i<=n;i++)s=s*x+a[i];//秦九韶公式,自行百度 
    return s; 
}

int main(){
    scanf("%d%lf%lf",&n,&l,&r);
    for(int i=0;i<=n;i++){
        scanf("%lf",&a[i]);
    }
    while(r-l>=eps){
        k=(r-l)/3.0;
        mid=l+k;
        mmid=r-k;
        if(f(mid)>f(mmid))r=mmid;
        else l=mid;
    }
    printf("%.5lf\n",l);
    return 0;
}

你可能感兴趣的:(洛谷 P3382 【模板】三分法)