zoukankan      html  css  js  c++  java
  • [NOI2005]月下柠檬树(计算几何+积分)

    题目描述

    李哲非常非常喜欢柠檬树,特别是在静静的夜晚,当天空中有一弯明月温柔 地照亮地面上的景物时,他必会悠闲地坐在他亲手植下的那棵柠檬树旁,独自思 索着人生的哲理。

    李哲是一个喜爱思考的孩子,当他看到在月光的照射下柠檬树投在地面上的 影子是如此的清晰,马上想到了一个问题:树影的面积是多大呢?

    李哲知道,直接测量面积是很难的,他想用几何的方法算,因为他对这棵柠 檬树的形状了解得非常清楚,而且想好了简化的方法。

    李哲将整棵柠檬树分成了 n 层,由下向上依次将层编号为 1,2,…,n。从第 1 到 n-1 层,每层都是一个圆台型,第 n 层(最上面一层)是圆锥型。对于圆台型, 其上下底面都是水平的圆。对于相邻的两个圆台,上层的下底面和下层的上底面 重合。第 n 层(最上面一层)圆锥的底面就是第 n-1 层圆台的上底面。所有的底面 的圆心(包括树顶)处在同一条与地面垂直的直线上。李哲知道每一层的高度为 h1,h2,…,hn,第 1 层圆台的下底面距地面的高度为 h0,以及每层的下底面的圆的 半径 r1,r2,…,rn。李哲用熟知的方法测出了月亮的光线与地面的夹角为 alpha。

    题解

    脑补一下这个影子长什么样子(反正我脑补不出来),是一堆圆和相邻两个圆之间构成的梯形构成,我们要求的就是这一大坨东西的面积。

    只需要保留两位小数,我们可以用自适应辛普森积分来求。

    然后注意高度要乘上三角函数,但半径不用,因为平面在竖直方向的投影长度为零。

    然后就是用计算几何乱搞(好恶心)

    细节还是挺多的,可能是我太菜了,斜边和直角边都搞错了。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #define N 602
    using namespace std;
    const double eps=1e-7;
    int n;
    double alpha,h[N],r[N];
    struct yuan{double x,r;}c[N];
    struct xianduan{double l,r,k,b;}l[N];
    inline xianduan _work(yuan a,yuan b){
        xianduan x;
        if((a.x-a.r<=b.x-b.r&&a.x+a.r>=b.x+b.r)||(b.x-b.r<=a.x-a.r&&b.x+b.r>=a.x+a.r))return x={0,0,0,0};
        if(fabs(a.r-b.r)<eps)return x={a.x,b.x,0,a.r};
        double r1=fabs(a.r-b.r),x1=b.x-a.x,zh=sqrt(x1*x1-r1*r1),co=zh/x1,si=r1/x1,x2=a.r/co,x3=b.r/co;
        x.k=(x3-x2)/x1;x.b=x2-a.x*x.k;        
        if(a.r>b.r)x.l=a.x+a.r*si,x.r=b.x+b.r*si;else x.l=a.x-a.r*si,x.r=b.x-b.r*si;    
        return x;
    }
    inline double F(double x){
        double ans=0;
        for(int i=1;i<=n;++i)if(c[i].x-c[i].r<=x&&c[i].x+c[i].r>=x)//勾股定理 
            ans=max(ans,sqrt(c[i].r*c[i].r-(x-c[i].x)*(x-c[i].x)));
        for(int i=1;i<n;++i)if(l[i].l<=x&&l[i].r>=x)ans=max(ans,x*l[i].k+l[i].b);
        return ans;
    } 
    inline double simpson(double l,double r){
        return (F(l)+F(r)+4*F((l+r)/2.0))*(r-l)/6.0;
    }
    double solve(double l,double r,double num){
        double mid=(l+r)/2.0,x=simpson(l,mid),y=simpson(mid,r);
        if(fabs(x+y-num)<eps)return num;
        else return solve(l,mid,x)+solve(mid,r,y);
    }
    int main(){
        scanf("%d%lf",&n,&alpha);alpha=1.0/tan(alpha); 
        for(int i=1;i<=n+1;++i)scanf("%lf",&h[i]);
        for(int i=1;i<=n;++i)scanf("%lf",&r[i]);++n;
        for(int i=1;i<=n;++i){
            h[i]*=alpha;c[i].x=h[i]+c[i-1].x;c[i].r=r[i];
        }    
        for(int i=1;i<n;++i)l[i]=_work(c[i],c[i+1]);
        double L=2e9,R=-2e9;
        for(int i=1;i<=n;++i){
            L=min(L,c[i].x-c[i].r);
            R=max(R,c[i].x+c[i].r);
        }
        printf("%.2lf",solve(L,R,simpson(L,R))*2);
        return 0;
    }
  • 相关阅读:
    2.4 自给自足的脚本:位于第一行的#!
    2.3 一个简单的脚本
    2.2 为什么要使用Shell脚本
    JSON 字符串 与 java 对象的转换
    ajax异步提交文件
    jquery选择器
    发现前端框架 bui-min.js
    学习hsf
    Git详解
    java学习材料
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10144794.html
Copyright © 2011-2022 走看看