三分法搜索
二分法适用于求单调的时候用的,就比如说排序好的数组,那是递增的或者递减的。如果像出现了非单调函数那样的怎么求它的最值呢?
二分法早就失去了他的意义了。不过还是可以用三分法来实现的,就是二分中再来二分。三分查找的算法,对于求凸性或凹性函数的极值非常方便
如图所示,已知左右端点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 来缩小范围。
摘自https://blog.csdn.net/littlewhite520/article/details/70144763
第一种写法
1 double solve(double l,double r) 2 { 3 double mid,midmid; 4 while(r - l > eps) 5 { 6 mid = (l + r)/2.0; 7 midmid = (r + mid)/2.0; 8 if(f(mid) <= f(midmid))// f 就算函数值 9 r = midmid; 10 else l = mid; 11 } 12 return f(l); 13 }
第二种写法
1 double three_devide(double low,double up) 2 { 3 double m1,m2; 4 while(up-low>=eps) 5 { 6 m1=low+(up-low)/3; 7 m2=up-(up-low)/3; 8 if(f(m1)<=f(m2)) 9 low=m1; 10 else 11 up=m2; 12 } 13 return (m1+m2)/2; 14 }
Light Bulb
Compared to wildleopard's wealthiness, his brother mildleopard is rather poor. His house is narrow and he has only one light bulb in his house. Every night, he is wandering in his incommodious house, thinking of how to earn more money. One day, he found that the length of his shadow was changing from time to time while walking between the light bulb and the wall of his house. A sudden thought ran through his mind and he wanted to know the maximum length of his shadow.
Input
The first line of the input contains an integer T (T <= 100), indicating the number of cases.Each test case contains three real numbers H, h and D in one line. H is the height of the light bulb while h is the height of mildleopard. D is distance between the light bulb and the wall. All numbers are in range from 10-2 to 103, both inclusive, and H - h >= 10-2.
Output
For each test case, output the maximum length of mildleopard's shadow in one line, accurate up to three decimal places..
Sample Input
3
2 1 0.5
2 0.5 3
4 3 4
Sample Output
1.000
0.750
4.000
设人到右墙边的距离为pos,整理得到人影关于pos的表达式((d-pos)*h-(H-h)*pos)/(d-pos) + pos,在这里pos的取值范围是(0,d*(h/(H*1.0)))
1 #include<stdio.h> 2 #define eps 1e-6 3 #define ll long long 4 using namespace std; 5 double H,h,d; 6 double f(double pos) 7 { 8 return((d-pos)*h-(H-h)*pos)/(d-pos) + pos; 9 } 10 double solve(double l,double r) 11 { 12 13 double mid,midmid; 14 while(r-l>=eps) 15 { 16 mid = (l + r)/2.0; 17 midmid = (r + mid)/2.0; 18 if(f(mid) >= f(midmid)) 19 { 20 r = midmid; 21 } 22 else 23 { 24 l = mid; 25 } 26 } 27 return f(l); 28 } 29 int main() 30 { 31 int t; 32 scanf("%d",&t); 33 while(t--) 34 { 35 double ans = 0 ; 36 scanf("%lf %lf %lf",&H,&h,&d); 37 ans = solve(0,d*(h/(H*1.0))); 38 printf("%.3lf\n",ans ); 39 } 40 }