bzoj2178 圆的面积并

2178: 圆的面积并

Time Limit: 20 Sec   Memory Limit: 259 MB
Submit: 1318   Solved: 341
[ Submit][ Status][ Discuss]

Description

给出N个圆,求其面积并

Input

先给一个数字N ,N< = 1000 接下来是N行是圆的圆心,半径,其绝对值均为小于1000的整数

Output

面积并,保留三位小数




Simpson积分裸题

P.S. 如何解决线段长度并:按左端点排序,然后记录当前右端点的最大值,扫一遍即可。




#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define ull unsigned long long
#define ld double
#define maxn 1005
#define inf 1e9
#define eps 1e-7
using namespace std;
int n,tot;
bool tag[maxn];
struct circle{ld x,y,r;}a[maxn],b[maxn];
struct segment{ld l,r;}p[maxn];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline bool cmpc(circle a,circle b)
{
	return a.r<b.r;
}
inline bool cmp(segment a,segment b)
{
	return a.l==a.r?a.r<b.r:a.l<b.l;
}
inline ld get(ld x)
{
	int cnt=0;
	F(i,1,n) if (fabs(x-a[i].x)<=a[i].r-eps)
	{
		ld tmp=sqrt(a[i].r*a[i].r-(x-a[i].x)*(x-a[i].x));
		p[++cnt]=(segment){a[i].y-tmp,a[i].y+tmp};
	}
	sort(p+1,p+cnt+1,cmp);
	ld h=-inf,ans=0;
	F(i,1,cnt)
	{
		if (h<p[i].l) ans+=p[i].r-p[i].l,h=p[i].r;
		else if (h<p[i].r) ans+=p[i].r-h,h=p[i].r;
	}
	return ans;
}
inline ld calc(ld l,ld r)
{
	ld mid=(l+r)/2;
	return (get(l)/6+get(mid)*2/3+get(r)/6)*(r-l);
}
inline ld simpson(ld l,ld r)
{
	ld mid=(l+r)/2,s1=calc(l,r),s2=calc(l,mid)+calc(mid,r);
	if (fabs(s2-s1)<=eps) return s2;
	else return simpson(l,mid)+simpson(mid,r);
}
int main()
{
	n=read();
	F(i,1,n) b[i].x=read(),b[i].y=read(),b[i].r=read();
	sort(b+1,b+n+1,cmpc);
	F(i,1,n-1) F(j,i+1,n)
		if ((b[i].x-b[j].x)*(b[i].x-b[j].x)+(b[i].y-b[j].y)*(b[i].y-b[j].y)<=(b[i].r-b[j].r)*(b[i].r-b[j].r))
		{
			tag[i]=true;
			break;
		}
	F(i,1,n) if (!tag[i]) a[++tot]=b[i];
	n=tot;
	printf("%.3lf\n",simpson(-2000.0,2000.0));
	return 0;
}


你可能感兴趣的:(bzoj,Simpson积分)