三分法主要用于求解一个函数在某个区间内的极大(极小)值点,类似于二分法做一个比较:
二分法 三分法
作用: 求解一个函数的零点 求解一个函数的极大(极小)值点
条件 函数在这个区间是单调函数 函数在这个区间是凸(凹)函数
首先对于一个凹函数y=f(x),我们要求它的极小值点。
首先确定它的极小值点所在的区间为[l,r]
计算出两个三分点:
mid=(l+r)/2
mid2=(mid+r)/2
(其实这两个点的位置是灵活的)
此时 l < mid <mid2 < r
计算出对应的函数值 f(mid)和f(mid2)。
当f(mid)<f(mid2)时,则极小值点一定不会在mid2和r之间。
反之f(mid)>f(mid2)时,极小值点一定该不会在l和mid之间。
因此,当f(mid)<f(mid2)时,极小值点在[l,mid2]内。此时令l=l,r=mid2继续计算。
当f(mid)>f(mid2)时,极小值点在[mid,r]内。此时令l=mid,r=r继续计算。
直到这个区间足够小,可以认为l=r时,l就是所求的极小值点。(可接受的误差内)
算法复杂度大约是log1.5((r-l)/eps)
double sanfen(double l,double r){ double mid,midmid,fmid,fmidmid; mid=(l+r)/2; midmid=(mid+r)/2; fmid=f(mid); fmidmid=f(midmid); while(r-l>0.00000000001){ //printf("%lf %lf %lf %lf ",mid,midmid,fmid,fmidmid); if(fmid>fmidmid){ l=mid; mid=midmid; fmid=fmidmid; midmid=(mid+r)/2; fmidmid=f(midmid); }else{ r=midmid; midmid=mid; fmidmid=fmid; mid=(l+midmid)/2; fmid=f(mid); } } return fmid; }
double f(double a) { /*返回函数值*/ } double Solve(double MIN,double MAX)//返回极值点 { double l = MIN, r = MAX; double mid, midmid; double mid_f, midmid_f; while (l + EPS < r) { mid = (l + r) / 2; midmid = (mid + r) / 2; mid_f = f(mid); midmid_f = f(midmid); // 假设求解最大极值.最小值则取小于号 if (mid_f >= midmid_f) r = midmid; else l = mid; } return l; }
模板1中稍微优化了一下,每次三分之需要多计算一次函数值,另一次直接利用上次计算出来的。
模板2中直接按照思路。