POJ1905[Expanding Rods]题解

来源:互联网 发布:sql三大部分 编辑:程序博客网 时间:2024/05/22 13:24

题目概述

有一根长len的木棍,加热了n度,长度会膨胀为len*(1+n*c),c为膨胀系数。现在把这根木棍夹在两堵墙之间,木棍会向上弯曲变成弧形,求弧形中点和原木棍中点的高度差。
这里写图片描述

解题报告

一道典型的二分题目,我们会想到直接二分答案dis,然后就可以计算出这个弧所在的圆的半径,紧接着就可以求出弧长。用求出的弧长与真正的弧长做对比来确定下一次二分的范围。

但是有个问题,怎么保证算出的弧长满足单调性?可以yy一下得到(我蒟蒻,并不会数学严格证明:P)。
1.dis小的时候:
这里写图片描述
2.dis大的时候:
这里写图片描述

在木棍原长度不变的情况下,dis越大,显然木棍越膨胀(yy……),所以弧长也就越大,满足单调性。

满足了单调性之后,我们就可以安心二分了,这里再详细说明一下如何求弧长:
这里写图片描述
根据勾股定理,我们知道(R-dis)^2+(len/2)^2=R^2,所以:
R^2-2*R*dis+dis^2+len^2/4=R^2
2*R*dis=dis^2+len^2/4
R=(dis+len^2/4/dis)/2
根据len’=2*θ*R=2*acos((R-dis)/R)*R(acos表示反三角函数,即知道cos值求角度(弧度制)),就可以得到弧长。
二分的范围:弧最多是半圆,所以dis最多是len/2。

特殊:当len=0或n=0或C=0时,答案就是0,最好特判掉。否则可能会造成被0除错误。

示例程序

#include<cstdio>#include<cmath>using namespace std;const double PI=3.14159265358;double len,n,C,len_; //len为原长度,len_为膨胀后的长度bool check(double dis){    double R=(dis+len*len/4/dis)/2;    return 2*acos((R-dis)/R)*R<=len_; //如果<=len_就验证成功}int main(){    freopen("program.in","r",stdin);    freopen("program.out","w",stdout);    scanf("%lf%lf%lf",&len,&n,&C);    while (len!=-1||n!=-1||C!=-1)    {        if (!len||!n||!C) {printf("0.000\n");scanf("%lf%lf%lf",&len,&n,&C);continue;} //特判        double L=1e-5,R=len/2,mid;len_=(n*C+1)*len;        while (L<=R)        {            mid=(L+R)/2;            if (check(mid)) L=mid+(1e-5); else R=mid-(1e-5); //验证成功就大一点,否则小一点        }        printf("%.3f\n",R);        scanf("%lf%lf%lf",&len,&n,&C);    }    return 0;}
0 0
原创粉丝点击