洛谷 P3382 【模板】三分法
洛谷 P3382 【模板】三分法
传送门
思路
这是一道三分的模板题
用于求单峰函数的极值
首先,在函数上标4个点:\(x=l,r,mid,mmid\)。其中\(mmid\)是\(mid\)与\(r\)的中点。(其实就是把函数三等分了)
然后我们需要通过迭代来缩小范围(\(while\)循环)
如果\(f(mid)>f(mmid)\),则\(mmid\)一定在峰的右边。
如果\(f(mid)<f(mmid)\),则\(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)<f(mmid)\)且\(mid\)在峰的右边。
由于\(f(x)\)在峰的右边单调递减,且\(f(mid)<f(mmid)\),所以\(mid\)在\(mmid\)的右边。
然而\(mmid = \frac{mid+rt}{2}\),显然\(mid\)在\(mmid\)左边。矛盾。
那么如何求\(f(n)\)呢
这就需要用到秦九韶公式了,大家可以自行百度,这里就不说了
代码
#include<bits/stdc++.h>
#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;
}