三分法

来源:互联网 发布:java 异步io 框架 编辑:程序博客网 时间:2024/06/11 17:11

转自:http://blog.csdn.net/pi9nc/article/details/9666627


我们都知道 二分查找 适用于单调函数中逼近求解某点的值。 
如果遇到凸性或凹形函数时,可以用三分查找求那个凸点或凹点。 
下面的方法应该是三分查找的一个变形。

这里写图片描述

如图所示,已知左右端点L、R,要求找到白点的位置。 
思路:通过不断缩小 [L,R] 的范围,无限逼近白点。 
做法:先取 [L,R] 的中点 mid,再取 [mid,R] 的中点 mmid,通过比较 f(mid) 与 f(mmid) 的大小来缩小范围。 
当最后 L=R-1 时,再比较下这两个点的值,我们就找到了答案。 
1、当 f(mid) > f(mmid) 的时候,我们可以断定 mmid 一定在白点的右边。 
反证法:假设 mmid 在白点的左边,则 mid 也一定在白点的左边,又由 f(mid) > f(mmid) 可推出 mmid < mid,与已知矛盾,故假设不成立。 
所以,此时可以将 R = mmid 来缩小范围。 
2、当 f(mid) < f(mmid) 的时候,我们可以断定 mid 一定在白点的左边。 
反证法:假设 mid 在白点的右边,则 mmid 也一定在白点的右边,又由 f(mid) < f(mmid) 可推出 mid > mmid,与已知矛盾,故假设不成立。 
同理,此时可以将 L = mid 来缩小范围。

这是先增再减的模型 凸型 
两种写法

int SanFen(int l,int r) //找凸点  {      while(l < r-1)      {          int mid  = (l+r)/2;          int mmid = (mid+r)/2;          if( f(mid) > f(mmid) )              r = mmid;          else              l = mid;      }      return f(l) > f(r) ? l : r;  }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
double three_devide(double low,double up)  {      double m1,m2;      while(up-low>=eps)      {          m1=low+(up-low)/3;          m2=up-(up-low)/3;          if(f(m1)<=f(m2))              low=m1;          else              up=m2;      }      return (m1+m2)/2;  }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

后面是先减再增 下凸 
和上面反着来

int SanFen(int l,int r) //找凸点  {      while(l < r-1)      {          int mid  = (l+r)/2;          int mmid = (mid+r)/2;          if( f(mid) > f(mmid) )              l = mid;          else              r = mmid;      }      return f(l) > f(r) ? l : r;  }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
double three_devide(double low,double up)  {      double m1,m2;      while(up-low>=eps)      {          m1=low+(up-low)/3;          m2=up-(up-low)/3;          if(f(m1)<=f(m2))              up=m2;          else              low=m1;      }      return (m1+m2)/2;  }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

原创粉丝点击