http://noi.openjudge.cn/ch0111/09/
- 总时间限制: 1000ms 内存限制: 65536kB
- 描述
-
当长度为L的一根细木棍的温度升高n度,它会膨胀到新的长度L‘=(1+n*C)*L,其中C是热膨胀系数。当一根细木棍被嵌在两堵墙之间被加热,它将膨胀形成弓形的弧,而这个弓形的弦恰好是未加热前木棍的原始位置。
你的任务是计算木棍中心的偏移距离。
输入
三个非负实数:木棍初始长度(单位:毫米),温度变化(单位:度),以及材料的热膨胀系数。
保证木棍不会膨胀到超过原始长度的1.5倍。
输出
木棍中心的偏移距离(单位:毫米),保留到小数点后第三位。
样例输入
1000 100 0.0001
样例输出
61.329
参考:
http://blog.csdn.net/jeremygjy/article/details/49686943
http://blog.csdn.net/txl199106/article/details/49332261
1 #include<stdio.h> 2 #include<math.h> 3 #define PI (acos(-1)) 4 #define eps (1e-14) 5 int main(int argc, char *argv[]) 6 { 7 double L,n,C,L1; 8 9 double minCentralAngle,maxCentralAngle,CentralAngle; 10 double radius,L2; 11 double ans; 12 13 scanf("%lf%lf%lf",&L,&n,&C); 14 15 if(n*C*L<=eps) //假如膨胀量太小就不用计算了,直接认为结果就是0. 16 { 17 printf("0.000\n"); 18 return 0; 19 } 20 21 L1=(1+n*C)*L; 22 23 //下面对圆心角进行二分枚举 24 //(膨胀量不超过原来的1.5倍, 25 //分析圆的半周长PI*R与直径2*R的关系可知圆心角范围0~2*PI而且不可能取2*PI) 26 minCentralAngle=0;//圆心角的极小值 27 maxCentralAngle=PI;//圆心角的极大值 28 while(minCentralAngle<maxCentralAngle-eps) 29 { 30 CentralAngle=(minCentralAngle+maxCentralAngle)/2; 31 radius=L/2/sin(CentralAngle/2); 32 L2=CentralAngle*radius; 33 if(L2>=L1)//当弦长固定时,圆心角越大 ,弧长就越大 34 maxCentralAngle=CentralAngle; 35 else if(L2<L1) 36 minCentralAngle=CentralAngle; 37 } 38 radius=L/2/sin(minCentralAngle/2); 39 ans=radius-L/2/tan(minCentralAngle/2); 40 printf("%.3lf\n",ans); 41 return 0; 42 }
一定要注意:我们需要二分的内容是当前角度,那么角度的范围可以很容易发现,因为木管长度不超过1.5倍那么就定角度为0-π因为如果圆心角过小会发现半径十分的大根本存不下,其实这种情况的时候木棍长度的变化也是十分的小的那么
if(n * c * L <= eps)
判断一下如果满足那么直接就输出0.000,
另外要注意:当弦长固定时,圆心角越大 ,弧长就越大 。
网友JeremyGJY的代码和分析很好,摘抄一下:
JeremyGJY的代码:
1 #include <cstdio> 2 #include <cmath> 3 #include <algorithm> 4 using namespace std; 5 const double PI = asin(1.0); 6 const double eps = 1e-14; 7 int main(){ 8 double Len1, Len2, Temp, ks; 9 while(scanf("%lf%lf%lf", &Len1, &Temp, &ks) != EOF){ 10 Len2 = (1.0 + Temp * ks) * Len1; 11 double l=0, r=PI; 12 if(Temp * ks * Len1 <= eps){ 13 printf("%.3lf\n", 0.0); 14 continue; 15 } 16 while(l < r - eps){ 17 double mid = (l + r)/2.0; 18 if(Len1/sin(mid)*PI*(mid/PI) >= Len2) 19 r = mid; 20 else l = mid; 21 } 22 printf("%.3lf\n", Len1/2/sin(l)-Len1/2/sin(l)*cos(l)); 23 } 24 25 return 0; 26 }
csdn网友Tank_long的分析更精彩,只不过下面这个图的公式似乎有点乱。
公式大概如下:
首先要注意θ角是圆心角的一半。然后根据数学公式有:
sinθ=2sin(θ/2)cos(θ/2)
1-cosθ=2sin(θ/2)2
然后还要注意根据直角三角形正弦的定义有:L=2*R*sinθ
根据弧长公式有LL=2*R*θ
所以h=R-R*cosθ=R*(1-cosθ)=L/(2*sinθ)*(1-cosθ)=L/(2*sinθ)*(2sin(θ/2)2)=L/( 2* ( 2*sin(θ/2)*cos(θ/2) ) )*(2sin(θ/2)2 )
最后h=L/2*tan(θ/2)
注意到θ是圆心角的一半,所以θ得区间是0~PI,根据正切函数图形性质可以知道当L固定时,h跟θ是成正比关系的。
Tank_long的代码:(不得不佩服起数学功底啊……)
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<math.h> 4 int main() 5 { 6 double l, ll, rig, lef, mid, n, c; 7 scanf("%lf%lf%lf", &l, &n, &c); 8 9 if(l<1e-14) 10 { 11 printf("0.000\n"); 12 return 0; 13 } 14 ll=l*(1+n*c); 15 lef=0.0; //角的极小值 16 rig=asin(1.0); //角的极大值 17 //由于三角函数转换,得到 h= (l/2)*tan(@/2) , 所以h只与角@有关,使用二分逼近法去求解最接近的@即可 18 //注意,二分验证是让 ll与角@ 计算得到的 木棍原始长度l`=ll*[email protected]/@ 与 l 进行比较,且l`与@成反比例关系 19 while(rig-lef>1e-14) //在极大值与极小值之间进行二分,这个地方精度控制太低就过不了了。精度要求很高。 20 { 21 mid=(rig+lef)/2; 22 if(ll*sin(mid)/mid<=l) 23 rig=mid; 24 else 25 lef=mid; 26 } 27 printf("%.3lf\n", l/2*tan(lef/2)); 28 return 0; 29 }