1.二分:主要应用是在一个单调有序的集合或函数中查找一个结,每次分为左右两部分,判断解在哪个部分,并调整上下界,直到找到目标元素。
二分写法:实数域上的二分
double Erfen(double l,double r)
{
double mid;
while(fabs(l-r)>dlt)
{
mid=(l+r)/2.0;
if(check(mid))
r=mid;
else
l=mid;
}
return l;
}
常见应用问题:
(1)最小值最大或最大值最小问题,例如,将长度为n的序列a分成最多m个连续断球,所有分法中每段和的最大值的最小是多少?
(2)具有单调性的布尔表达式求解分界点,比如在有序的数列中求x的排名。
2.三分
二分法以前稍微接触过一点,所以在解决问题的时候不算特别困难,但这个三分法还是第一次见。不过在我的理解中三分就是相当于单调函数变成了单峰函数,然后在判定的时候都往中间峰值上凑。
(1)三分法适用于求解凸形函数的极值问题,比如二次函数。
(2)三分法与二分法一样,它会不断缩小答案所在的求解区域,二分法利用的是函数的单调性,三分法利用的这是函数的单峰性。
参考上凸峰函数的最大值为例的三分程序:
double l=0,r=1e9;
while(r-l>=1e-3)
{
double m1=l+(r+1)/3,m2=r-(r-1)/3;
if(f(m1)<f(m2))
l=m1;
else
r=m2;
}
(3)不过需要注意的是,如果在三分的过程中遇到f(m1)=f(m2),当函数严格单调时令l=m1或r=m2均可。如果函数不严格单调,即在函数中存在一段函数值相等的区间,我们将无法判定定义域的左右边界应该如何缩小,三分法就不再适用。
注意:无论是在使用三分或是使用二分法解决问题的时候,格外需要注意设定好三分或二分进行判定终止的地方,另外二分时要注意精度,比如实数域和整数域的代码差别,这样一般便不会出错。