• 三分求单峰/单谷函数极值


    单峰函数:拥有唯一的极大值点,在极大值点左侧严格单增,右侧严格单减。函数值先增大后减小。

    单谷函数:拥有唯一的极小值点,在极小值点左侧严格单减,右侧严格单增。函数值先减小后增大。

    1.求单峰函数的极大值点:

    在函数定义域[left,right]上取两个点lmid和rmid将函数分为三段。

    (1)若f(lmid)

    (2)同理,若f(lmid)>f(rmid),则极大值点一定在rmid左侧,因此可令right=rmid。

    lmid=left+(right-left)/3=(2*left+right)/3;

    rmid=right-(right-left)/3=(left+2*right)/3;

    1. //求解极大值点
    2. double th_division(double left,double right,double eps){
    3. double lmid,rmid;
    4. while(left+eps<right){
    5. lmid=(2*left+right)/3;
    6. rmid=(left+2*right)/3;
    7. if(f(lmid)<f(rmid)){
    8. //表明lmid和rmid要么在同侧且上升,那么lmid肯定在波谷的左边
    9. //所以令left=lmid;
    10. left=lmid;
    11. }
    12. //否则令right=rmid;
    13. else right=rmid;
    14. }
    15. return lmid;
    16. }

    2.求单谷函数的极小值点

    原理同上

    1. //求解极小值点
    2. double th_division(double left,double right,double eps){
    3. double lmid,rmid;
    4. while(left+eps<right){
    5. lmid=(2*left+right)/3;
    6. rmid=(left+2*right)/3;
    7. if(f(lmid)>f(rmid)){
    8. //表明lmid和rmid要么在同侧且下降,那么lmid肯定在波谷的左边
    9. //所以令left=lmid;
    10. left=lmid;
    11. }
    12. //否则令right=rmid;
    13. else right=rmid;
    14. }
    15. return lmid;
    16. }

    例题:

    HDOJ2438 Turn the corner

    题意:

    给出转角的两个宽度x,y和车的长度和宽度l和d,问车能否成功通过转角。

    思路:

    如图:

    转弯时,假设汽车的一边紧贴转角,

    则要想通过转角,则需

     h<y

    因为h=lcos\theta -pcos\theta

    又因为   sin\theta =\frac{x-\frac{D}{cos\theta }}{p}

    所以p=\frac{x-\frac{D}{cos\theta }}{sin\theta }

    我们发现随着\theta从0°增长到90°,h先增大后减小,是凸性函数。因此用三分求出极大值点,如果最大值<=y,表明可以通过转角,否则不能通过。

    代码:

    1. #include <bits/stdc++.h>
    2. using namespace std;
    3. typedef long long ll;
    4. const double pi=acos(-1.0),eps=1e-10;
    5. double x,y,l,d;
    6. double f(double seta){//seta即为图中的角
    7. double p=(x-d/cos(seta))/sin(seta);
    8. double h=l*cos(seta)-p*cos(seta);
    9. //seta角从0°增长到90°,h先增大后减小,为凸性函数,因此利用三分求极大值点
    10. return h;
    11. }
    12. int main(){
    13. while(scanf("%lf%lf%lf%lf",&x,&y,&l,&d)!=EOF){
    14. double left=0.0,right=pi/2;
    15. double lmid,rmid;
    16. while(left+eps<right){//三分
    17. lmid=(2*left+right)/3;
    18. rmid=(left+2*right)/3;
    19. if(f(lmid)<f(rmid)){
    20. left=lmid;
    21. }
    22. else right=rmid;
    23. }
    24. //如果最大值f(left)<=y,表示可以通过
    25. if(f(left)<=y) puts("yes");
    26. else puts("no");
    27. }
    28. return 0;
    29. }

    ZOJ 3203 Light Bulb

    题意:

    给出H,h,D,求影子的长度。

    思路:

    影子的长度为地上的和墙上的影子长度之和。

    利用角度和相似三角形可以求出len的表达式,发现随着x从小到大,len先增大后减小,因此为凸性函数,利用三分求解。

     

    代码:

    1. #include <bits/stdc++.h>
    2. using namespace std;
    3. typedef long long ll;
    4. const double pi=acos(-1.0),eps=1e-10;
    5. double H,h,D;
    6. double f(double x){
    7. return D-x+h-(D-x)*(H-h)/x;
    8. }
    9. int main(){
    10. int t;
    11. scanf("%d",&t);
    12. while(t--){
    13. scanf("%lf%lf%lf",&H,&h,&D);
    14. double left=0.0,right=D;
    15. double lmid,rmid;
    16. while(left+eps<right){//三分
    17. lmid=(2*left+right)/3;
    18. rmid=(left+2*right)/3;
    19. if(f(lmid)<f(rmid)){
    20. left=lmid;
    21. }
    22. else right=rmid;
    23. }
    24. printf("%.3lf\n",f(left));
    25. }
    26. return 0;
    27. }

  • 相关阅读:
    图像分割 - Hough变换直线检测
    css3 文本超出容器后显示...以及超出几行后显示...
    快速排序图解(两种思想)
    Linux下,C++判断指定路径下,是否存在wps打开的文件
    DLang 与 C 语言交互(一)
    通过WARN(1,“xxx“) 来确定code的flow和打印callstack
    Hikyuu 1.3.0 发布,高性能量化交易研究框架
    2011-2019年各省农村人均受教育年限和村委会个数数据
    【18年扬大真题】已知a数组int a[ ]={1,2,3,4,5,6,7,8,9,10},编写程序,求a数组中偶数的个数和偶数的平均值
    【LeetCode】最小区间 [H](贪心)
  • 原文地址:https://blog.csdn.net/srh20/article/details/126806838