【二分】POJ1905[Expanding Rods]题解

题目概述

有一根长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;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值