BZOJ 2178 圆的面积并 Simpson积分

题意:链接

方法: Simpson积分

解析:

这题是有正解的=-=

不过Simpson积分可过。

首先

rlf(x)=(rl)(f(l)+f(r)+4f(mid))6

然后就强行递归搞就行了。

至于f(i)的值,在本题就是x=i这条直线与所有可以相交的圆的截线长的和。

这个的话用勾股定理求即可。

然后有一个方法

Simpson积分自适应法=-=

我们只需要强行套用公式,然后检验左半边的如上函数值加上右半边的如上函数值与我们强行套用公式得出来的值是否在精度范围允许内,如果在的话直接return值就好了,不在的话继续递归搞。

本题精度范围需要定到1e-13

但是还不够。

依然会T。

所以需要剪枝。

两个剪枝。

首先把所有被内含的圆删掉。

其次我们可以一段一段的求simpson值,累加。

因为中间可能会有空的部分。

代码:

#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 1100
#define pr pair<double,double>
#define Fabs(x) ((x)>0?(x):-(x))
using namespace std;
const double pi=acos(-1.0);
const double EPS=1e-13;
const double INF=1e100;
struct Point
{
    int x,y;
    friend double dis(Point a,Point b)
    {
        return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
};
struct Circle
{
    Point p;
    int r;
    void read(){scanf("%d%d%d",&p.x,&p.y,&r);}
    friend bool operator <(Circle a,Circle b)
    {
        if(a.p.x-a.r<b.p.x-a.r)
            return a.p.x+a.r<b.p.x+a.r;
        return a.p.x-a.r<b.p.x-a.r;
    }
    pr f(double x)
    {
        if(r<=fabs(p.x-x))  return pr(0,0);
        double t=r*r-(p.x-x)*(p.x-x);
        t=sqrt(t);
        return pr(p.y-t,p.y+t);
    }
}O[N];
bool ban[N];
pr p[N];
int n;
double Cut(double x)
{
    double ret=0,last=-INF;
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        p[++cnt]=O[i].f(x);
        if(p[cnt]==pr(0,0))
            cnt--;
    }
    sort(p+1,p+cnt+1);
    for(int i=1;i<=cnt;i++)
    {
        if(p[i].first>last)
            ret+=p[i].second-p[i].first,last=p[i].second;
        else if(p[i].second>last)
            ret+=p[i].second-last,last=p[i].second;
    }
    return ret;
}
double Simpson(double l,double r,double mid,double Cl,double Cr,double Cm)
{
    double tCl=Cut((l+mid)/2),tCr=Cut((mid+r)/2);
    double ans=(r-l)*(Cl+Cr+4*Cm)/6,lans=(mid-l)*(Cl+Cm+4*tCl)/6,rans=(r-mid)*(Cr+Cm+4*tCr)/6;
    if(Fabs(lans+rans-ans)<EPS)
        return ans;
    else
        return Simpson(l,mid,(l+mid)/2,Cl,Cm,tCl)+Simpson(mid,r,(mid+r)/2,Cm,Cr,tCr);
}
int main()
{
    int i,j,k;
    double l,r;
    scanf("%d",&n);
    l=INF,r=-INF;
    for(i=1;i<=n;i++)
    {
        O[i].read();
        l=min(l,(double)O[i].p.x-O[i].r);
        r=max(r,(double)O[i].p.x+O[i].r);
    }
    sort(O+1,O+n+1);
    for(i=1;i<=n;i++)
    {
        if(ban[i])  continue;
        for(j=i+1;j<=n;j++)
        {
            if(ban[j])  continue;
            if(dis(O[i].p,O[j].p)+O[j].r<=O[i].r)
                ban[j]=1;
        }
    }
    for(i=1;i<=n;i++)
    {
        if(ban[i])
        {
            swap(ban[i],ban[n]);
            swap(O[i--],O[n--]);
        }
    }
    printf("%.3lf\n",Simpson(l,r,(l+r)/2,0,0,Cut((l+r)/2)));
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值