三分/优选法(黄金分割法)求单峰函数极值

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

(此题其实当然可以取导用二分做,但是如果有些函数求导很麻烦的话那就用三分)

三分:
此题根据对称性,在(l,r)中间找两个点l',r',若f(l')<f(r')那就取(l',r)否则取(l,r')  -----其实可以看成粗糙的取导

double f(double x){//秦九昭
double ans=0,k=1;
FFor(i,n,0)ans+=k*a[i],k*=x;
return ans;
}

普通三分

double work(double l,r){
while(fabs(r-l)>eps){
lm=l+(r-l)/3;
rm=r-(r-l)/3;
if(f(rm)>=f(lm))l=lm;
else r=rm;
}
printf("%.5f",l);

优选法三分:
我看了网上大量博客文章,大多数真心没说到点子上(而且代码也没体现出优化性)
实际上就一句话,普通的三分(或者你随意按其他比例缩小范围)都是每次必须取两个点进行计算f(l+len*w),f(r-len*w),
但黄金分割法除了第一次取两个点外,以后每次就只需要取一个点就OK了,你说快不快。
如图,红点是必须计算的点,灰点因为上一轮已经计算过,所以此轮就不用计算了,这样就实现了每轮只计算一个点的效果


黄金分割数为 (sqrt(5)-1)/2 就不证明了

上代码:

#define gor (sqrt(5)-1)/2
bool fgl=true,fgr=true;

double gold(double l,r){
while(fabs(r-l)>eps){
double midr=(r-l)*gor+l;
double midl=r-(r-l)*gor;
if(!fgr)fr=f(midr);
if(!fgl)fl=f(midl);
if(fl>fr)
r=midr,fgr=true,fgl=false;
else if(fl<fr)
l=midl,fgl=true,fgr=false;
else 
l=midl,r=midr,fgr=true,fgl=true;
}
return r;
}
printf("%.5f",gold(l,r));
原文地址:https://www.cnblogs.com/planche/p/9395378.html