SPOJ The area of the union of circles 自适应辛普森积分

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/87186250

题意:求多个圆形区域的并的面积。圆的数量 n < = 1000 n <= 1000
我们设 f ( a ) = ( x = a 线 ) f(a)=(x=a这条直线在圆形区域内的长度) , 那么答案就是 f ( x ) d x \int f(x)\rm {d} x
然后就可以直接用自适应辛普森积分来近似答案。 e p s = 1 e 6 eps = 1e-6 可过。
计算 f ( x ) f(x) O ( n log n ) O(n \log n)
但是(所以)我们需要卡常(毕竟这是玄学算法)。
1.辛普森积分在不连续的地方效率会降低,那么就把圆分成多组,每组的分别计算,因为每组内 f f 是连续的。
2.如果一个圆被另一个圆包含,就删掉这个圆(效果很好)。
AC Code;

#include<bits/stdc++.h>
#define maxn 1005
#define eps 1e-6
using namespace std;

int n;
struct Cir
{
	double x,y,r,L,R;
	bool operator <(const Cir &B)const{ return L<B.L; }
}O[maxn];
double sqr(double a){ return a*a; }
vector<Cir>C;
map<double,double>mp;
double ans = 0;
vector<pair<double,double> >st;
double f(double a)
{
	if(mp.count(a)) return mp[a];
	st.clear();
	for(int i=0,siz=C.size();i<siz;i++)
		if(fabs(C[i].x-a)<C[i].r)
		{
			double dis = C[i].x-a , u = sqrt(sqr(C[i].r)-sqr(dis)) , l , r;
			l = C[i].y - u , r = C[i].y + u;
			st.push_back(make_pair(l,r));
		}
	sort(st.begin(),st.end());
	double mx=-0x3f3f3f3f,ret=0;
	for(vector<pair<double,double> >::iterator it=st.begin();it!=st.end();it++)
	{
		mx = max(mx , (*it).first);
		ret+=max(0.0,(*it).second-mx);
		mx = max(mx , (*it).second);
	}
	mp[a] = ret;
	return ret;
}

double calc(double a,double b,double c,double Fa,double Fb,double Fc)
{
	return (Fa + 4 * Fb + Fc) / 6 * (c-a);
}

void solve(double l,double r)
{
	double mid = (l+r) * 0.5,mid1=(l+mid)*0.5,mid2=(r+mid)*0.5;
	double F[5]={f(l),f(mid1),f(mid),f(mid2),f(r)};
	double lv = calc(l,mid1,mid,F[0],F[1],F[2]),rv=calc(mid,mid2,r,F[2],F[3],F[4]),v=calc(l,mid,r,F[0],F[2],F[4]);
	if(fabs(v-lv-rv)<eps){ ans+=lv+rv;return; }
	solve(l,mid),solve(mid,r);
}

bool ban[maxn];

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&O[i].x,&O[i].y,&O[i].r),O[i].L=O[i].x-O[i].r,O[i].R=O[i].x+O[i].r;
	sort(O+1,O+1+n);
	double mx = -0x3f3f3f3f,pre;
	for(int i=1;i<=n;i++) 
		for(int j=1;j<=n;j++)
			if(i!=j)
			{
				double dis = sqrt(sqr(O[i].x-O[j].x)+sqr(O[i].y-O[j].y));
				if(O[j].r > dis)
				{
					if(dis + O[i].r < O[j].r - eps)
						ban[i] = 1;
				}
			}
	for(int i=1;i<=n;i++)
		if(!ban[i]){
			if(O[i].L>mx)
			{
				if(C.size())
				{
					solve(pre,mx);
					C.clear();
					mp.clear();
				}
			}
			if(C.empty()) pre = O[i].L;
			C.push_back(O[i]);
			mx = max(O[i].R,mx);
		}
	if(C.size())
		solve(pre,mx);
	printf("%.3lf\n",ans);
}//asdf

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/87186250
今日推荐