Expanding Rods POJ1905 二分

http://poj.org/problem?id=1905

这个题目其实想到了方法一点都不难,但是一般想到方法也不过是找到了一个关于r和sita的表达式,然后进行行二分或三分求解。

所以一般的求解显得复杂,参考了大神的解法之后,真心觉得ACM算法之路好有好长。

简述一下大神的做法:

大神选择了直接二分高度,通过高度和弦长推出半径,再算角度,最后与实际的弧长进行比较,并最后进行调整。

这种算法的好处有以下几点;

1.使用相交弦定理,一步求出半径(真不知大神怎么还会记得相交弦定理啊,这数学基础!!!!!)

2,只在求sita时使用了一次反三角函数,不像其他的算法,反复的求三角正弦,余弦啊各种·····尽量保留了精度。

3,突破以往的二分模式,并不求关于高度的calcu表达式,而是间接利用,以判断大小

4,最后,我觉得最神奇的是大神在复杂的题意下,找到了一个非常简洁的单挑函数:依题长度增加做多不过一半,也就是其形成的扇形组最大不过是半圆,那么在弦长一定的时候,给一个弧高就可以确定一个园,进而可以确定这段弧长。

反正我自己觉得这个算法很牛,不知读者怎么想,再次表达一下对这些大神们神一样的解题思路的无限敬仰。

这是我按照思路,自己写的代码,读者应该能写出更好的:

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<cstring>
 4 using namespace std;
 5 #define eps 1e-4
 6 double l,c,ls,n,r,sita;
 7 double solve(double a,double b)
 8 {
 9     double left,right,mid;
10     left=a;
11     right=b;
12     while(left+eps<right)
13     {
14 
15         mid=(left+right)/2;
16         r=l*l/8/mid+mid/2;
17         //sita = acos(1-l*l/r/r/2);
18         sita=2*asin(l/2/r);
19         if(sita*r>=ls)
20             right=mid;
21         else
22             left=mid;
23     }
24     return left;
25 }
26 int main()
27 {
28     while(~scanf("%lf%lf%lf",&l,&n,&c))
29     {
30         if(l<0||n<0||c<0)break;
31         ls=l*(1+n*c);
32         printf("%.3f
",solve(0,l/2));
33     }
34     return 0;
35 }
原文地址:https://www.cnblogs.com/plank-george-zzo/p/3245621.html