POJ 1905 - Expanding Rods 【二分/三分】

题目链接:http://poj.org/problem?id=1905

题意:

一根两端固定在两面墙上的杆 受热弯曲后变弯曲

求前后两个状态的杆的中点位置的距离

思路:如图所示,已知s,a 求x。设角度为rad,半径为r, 显然,我们有r = s/ rad = a/sin(rad);即a*rad-s*sin(rad)=0或者rad/sin(rad) = s/a。下面我们就根据这两个式子进行二分或三分。

法一:令函数f(rad) = rad/sin(rad) ,求导找单调性,f'(rad) = (sin(rad)-rad*cos(rad))/sin^2(rad) = cos(rad)/sin^2(rad)*(tan(rad)-rad),rad∈(0,π),故tan(rad)-rad>0;所以函数f(rad) 单调递增。接下来就对函数直接二分吧~

法二:令函数f(rad) = a*rad-s*sin(rad),目标是求函数的零点,当时我还没有去求导,直接就拿三分上,其实求下 导也是很容易的。下面讲讲我的思路吧。rad∈(0,π)不变,我在没有求导的情况下,也就是说在我还不知道函数的单调性的时候,但是在定义域范围内我知道单调区间最多就是两个,那么这个时候我就直接三分搜索答案了~

最后提醒大家一下,提交的时候注意不要用G++来提交printf("lf"),否则会WA,而C++可以AC,如果要用G++提交,大家不妨用cout<<fixed<<setprecision().....


/**
 *作者:__Xiong
 *日期:2015/7/24
 */
 //法一:二分
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
const double eps = 1e-10;
const double PI = 3.1415926535897932384626433832795;
double N,C,L;
int main()
{
    //freopen("input.in","r",stdin);
    while(scanf("%lf%lf%lf",&L,&N,&C)&&N>=0&&C>=0&&L>=0)
    {
        if(N==0||L==0||C==0)
        {
            printf("0.000\n");
            continue;
        }
        double minv = 0,maxv = acos(-1.0), midv;
        double L2 = ( 1 + N * C ) * L;
        while(maxv - minv > 1e-12)
        {
            midv = (minv + maxv) / 2;
            if( 2 * L2 / L > midv / sin(midv / 2))
                minv = midv;
            else    
                maxv = midv;
        }
        //printf("%.3lf\n",L2 / midv * (1-cos(midv / 2)));G++提交不要用prinf("lf")
    }
    return 0;
}
//法二:三分
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
const double eps = 1e-10;
const double PI = 3.1415926535897932384626433832795;
double L,C,N,a,s,r,rad,ans;
double Calc(double x) { return fabs(a*x-s*sin(x)); }
void Search() {
    double l,r,mid,midmid,mVal,mmVal;
    l = 0,r = PI/2.0;
    while(r-l>=eps)
    {
        mid = (l+r)/2.0;midmid = (mid+r)/2.0;
        mVal = Calc(mid);mmVal = Calc(midmid);
        if(mVal > mmVal)
        {
            rad = midmid;
            l = mid;
        }
        else if(mVal < mmVal)
        {
            rad = mid;
            r = midmid;
        }
        else
        {
            rad = (mid+midmid)/2.0;
            l = mVal;
            r = mmVal;
        }
    }
    ans = s/rad*(1.0-cos(rad));
    printf("%.3lf\n",ans);//G++提交不要用prinf("lf")
}
int main() {
    //freopen("input.in","r",stdin);
    while(~scanf("%lf %lf %lf",&L,&N,&C))
    {
        if(L<0) break;
        if(N==0||L==0||C==0)
        {
            printf("0.000\n");
            continue;
        }
        s = (1.0+N*C)*L/2.0;
        a = L/2.0;
        Search();
    }
    return 0;
}


  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值