bzoj-2178 圆的面积并

题意:

给出平面上的n个圆,求它们的面积并;

n<=1000;

题解:

这题似乎有很多种姿势来解,我学了一种比较Simple的;

对于三次以下多项式函数的定积分,有一个Simpson公式:

∫[l,r]f(x)=(r-l)(f(l)+f(r)+4f(mid))/6

公式可以利用导数证明,但是对于三次以上或者其他函数是不成立的;

比如圆的参数方程,三角函数之类的奇怪东西;

虽说如此,不成立的时候,也可以利用这个公式来干点什么。。

利用这个公式来拟合曲线!

对于一段区间[l,r],我们求得f(l),f(r),f(mid);

然后直接带入公式,就得到了过三个点的二次函数曲线的面积;

这并不一定是解,但是离解应该也比较接近;

所以验证一下,再套[l,mid]与[mid,r]的公式,也可以得到一个这个区间的面积;

如果这两个面积差不多那答案就差不多啦,如果差的很多呢?

递归计算!

分别对[l,mid],[mid,r]区间递归算值,一直递归到可以接受的地步;

这个过程将曲线划分越来越细,然后对每一段拟合一个函数曲线;

像是一个适应曲线的过程(?),所以这个算法被称为Simpson自适应法;

这个算法显然不够完美,比如面对非连续函数几乎无法得到正确结果;

即使是连续函数也可以构造出很多的神奇数据卡掉算法(BZOJ这道题并没有卡就是了);

对策就是在验证以及递归计算的时候随机分段,或者分成多段;

这样时间效率会慢一些但是被卡的几率降低了很多;

BZOJ2178有些卡常数,EPS到1e-13也真是丧心病狂;

代码:

#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;
}
时间: 2024-12-01 17:56:17

bzoj-2178 圆的面积并的相关文章

BZOJ 2178: 圆的面积并 [辛普森积分 区间并]

2178: 圆的面积并 Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 1740  Solved: 450[Submit][Status][Discuss] Description 给出N个圆,求其面积并 Input 先给一个数字N ,N< = 1000 接下来是N行是圆的圆心,半径,其绝对值均为小于1000的整数 Output 面积并,保留三位小数 太可怕了!!!!!! 直接上辛普森积分 函数值就是x=..线上的区间并 区间并直接排序扫描就可以了

BZOJ 2178 圆的面积并 Simpson自适应公式

题目大意:给定n个圆,求面积并 直接暴力套用Simpson自适应公式就行了 对于每一个x值,求出F(x)的方法是求出所有圆在直线x=x(重了233)上的截取区间 然后求区间并 返回区间长度即是F值 这样正常写就过样例了 然后 WA了... 尼玛我样例都过了你跟我说WA? 下面是注意事项: 1.此题卡精度 EPS要设为1e-13 设为1e-12会WA 2.标程精度不够 不能用long double 否则会WA 3.这样会TLE 解决方法是预先将内含与其他圆的圆删掉 然后就能过了 这明显是卡数据啊-

BZOJ 2178 圆的面积并 Simpson积分

题意:链接 方法: Simpson积分 解析: 这题是有正解的=-= 不过Simpson积分可过. 首先 ∫rlf(x)=(r?l)(f(l)+f(r)+4f(mid))6 然后就强行递归搞就行了. 至于f(i)的值,在本题就是x=i这条直线与所有可以相交的圆的截线长的和. 这个的话用勾股定理求即可. 然后有一个方法 Simpson积分自适应法=-= 我们只需要强行套用公式,然后检验左半边的如上函数值加上右半边的如上函数值与我们强行套用公式得出来的值是否在精度范围允许内,如果在的话直接retur

bzoj 2178 圆的面积并【simpson积分】

直接套simpson,f可以直接把圆排序后扫一遍所有圆,这样维护一个区间就可以避免空段. 然而一定要去掉被其他圆完全覆盖的圆,否则会TLE #include<iostream> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; const double eps=1e-13; const int N=1005; int n,m; double mn=1e13,mx

BZOJ 2178 圆的面积并 ——Simpson积分

[题目分析] 史上最良心样例,史上最难调样例. Simpson积分硬上. 听说用long double 精度1e-10才能过. 但是double+1e-6居然过了. [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #incl

【BZOJ】2178: 圆的面积并

http://www.lydsy.com/JudgeOnline/problem.php?id=2178 题意:给出n<=1000个圆,求这些圆的面积并 #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> #include <queue> #in

【BZOJ】【2178】圆的面积并

自适应辛普森积分 Orz Hzwer 辛普森真是个强大的东西……很多东西都能积= = 这题的正解看上去很鬼畜,至少我这种不会计算几何的渣渣是写不出来……(对圆的交点求图包,ans=凸包的面积+一堆弓形的面积,另外还有中空的情况……那种凸包怎么求啊喂!) 1 /************************************************************** 2 Problem: 2178 3 User: Tunix 4 Language: C++ 5 Result: A

POJ 2546 &amp; ZOJ 1597 Circular Area 两圆的面积交

Circular Area Time Limit: 2 Seconds      Memory Limit: 65536 KB Your task is to write a program, which, given two circles, calculates the area of their intersection with the accuracy of three digits after decimal point. Input In the single line of in

BZOJ 1845: [Cqoi2005] 三角形面积并 [计算几何 扫描线]

1845: [Cqoi2005] 三角形面积并 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 1151  Solved: 313[Submit][Status][Discuss] Description 给出n个三角形,求它们并的面积. Input 第一行为n(N < = 100), 即三角形的个数 以下n行,每行6个整数x1, y1, x2, y2, x3, y3,代表三角形的顶点坐标.坐标均为不超过10 ^ 6的实数,输入数据保留1位小数 Out

java定义一个Circle类,包含一个double型的radius属性代表圆的半径,一个findArea()方法返回圆的面积

需求如下:(1)定义一个Circle类,包含一个double型的radius属性代表圆的半径,一个findArea()方法返回圆的面积. (2)定义一个类PassObject,在类中定义一个方法printAreas(),该方法的定义如下: public void printAreas(Cirlce c, int times) 在printAreas方法中打印输出1到time之间的每个整数半径值,以及对应的面积.例如,times为5,则输出半径1,2,3,4,5,以及对应的圆面积. 在main方法