[BZOJ1502][NOI2005]月下檸檬樹(辛普森積分+解析幾何)

題目:

我是超鏈接

題解:

首先我們理解一下投影的性質,也就是投影出來的圖形一定跟原圖形全等。
考慮一下圓形投影下來是什麼呢?和原來一樣的圓形啊

怎麼轉化豎着的樹呢?
這裏寫圖片描述

也就是樹高*cot(α)

那麼我們所要求的就是一些圓形和一些等腰梯形面積並

樣例圖片是這樣的
這裏寫圖片描述

那麼運用計算幾何的知識就可以得到圓的方程和圓的公切線的方程,然後得到一個連續的函數(這樣用辛普森積分的時候就不必考慮將整個圖形拆成若干個一坨一坨的圖形再求積分)。最後這個題就成爲一個函數的解析式,這個函數關於x軸對稱,求這個函數與X軸之間的面積,因爲對稱,*2就行了

微積分啊。

套用辛普森積分:Simpson(l,r) = (F(l) + F(r) + F(mid) * 4) * (r - l) / 6.0,然後遞歸檢查精度,如果左值+右值-總值的絕對值小於精度就返回,否則就遞歸返回左側面積和右側面積。得到一個近似精確的值就是所求的答案。

辛普森積分:不能求出精確解,但是可以近似地求出一些微積分不能夠求解的圖像的面積。

代碼:

#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
const int N=1005;
const double eps=1e-6;
int n;
struct hh{
    double x,y;
    hh(double X=0,double Y=0){x=X;y=Y;}
}a[N],s[N],e[N];
double pf(double x){return x*x;}
void cl(int i)
{
    if (fabs(a[i+1].y-a[i].y)<eps){e[i]=a[i+1];s[i]=a[i];return;}
    double si=(a[i+1].y-a[i].y)/(a[i+1].x-a[i].x);
    e[i].x=a[i+1].x-a[i+1].y*si;
    e[i].y=sqrt(pf(a[i+1].y)-pf(a[i+1].y*si));
    s[i].x=a[i].x-a[i].y*si;
    s[i].y=sqrt(pf(a[i].y)-pf(a[i].y*si));
}
double f(double x)//在x位置最大的y值,也就是在表面上的值 
{
    double y=0;
    for (int i=1;i<=n+1;i++)
        if (fabs(a[i].x-x)<=a[i].y)//圓內
          y=max(y,sqrt(pf(a[i].y)-pf(a[i].x-x)));
    for (int i=1;i<=n;i++)
        if (a[i+1].x-a[i].x+a[i].y>a[i+1].y && x<=e[i].x && x>=s[i].x)
          y=max(y,(e[i].y-s[i].y)/(e[i].x-s[i].x)*(x-s[i].x)+s[i].y);
    return y;
}
double work(double L ,double R)
{
    double mid=(L+R)/2;
    return (f(L)+f(R)+f(mid)*4)*(R-L)/6;
}
double Simpson(double L,double R)
{
    double mid=(L+R)/2;
    double x1=work(L,mid),x2=work(mid,R),x3=work(L,R);
    if (fabs(x1+x2-x3)<eps) return x1+x2;
    else return Simpson(L,mid)+Simpson(mid,R);
}
int main()
{
    double tha;
    scanf("%d%lf",&n,&tha);
    tha=1/tan(tha);
    double h=0;
    for (int i=1;i<=n+1;i++)
    {
        double x;scanf("%lf",&x);
        h+=x; a[i].x=tha*h;
    }
    for (int i=1;i<=n;i++) scanf("%lf",&a[i].y);
    double L=a[1].x,R=a[n+1].x;
    for (int i=1;i<=n;i++) 
    {
        L=min(L,a[i].x-a[i].y);
        R=max(R,a[i].x+a[i].y);
        if (a[i+1].x-a[i].x+a[i].y>a[i+1].y) cl(i);
    }
    printf("%.2lf",2*Simpson(L,R));
}
發佈了722 篇原創文章 · 獲贊 547 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章