[BZOJ 2178] 圆的面积并 【Simpson积分】

题目链接:BZOJ - 2178

 

题目分析

用Simpson积分,将圆按照 x 坐标分成连续的一些段,分别用 Simpson 求。

注意:1)Eps要设成 1e-13  2)要去掉被其他圆包含的圆。

 

代码

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

typedef double LF;

const LF Eps = 1e-13;

const int MaxN = 1000 + 5;

int n, Lc, Rc, Top, Tot;

LF Lx, Rx, Ans;

inline LF gmin(LF a, LF b) {return a < b ? a : b;}
inline LF gmax(LF a, LF b) {return a > b ? a : b;}
inline LF Sqr(LF x) {return x * x;}

struct Point
{
	LF x, y;
	Point() {}
	Point(LF a, LF b)
	{
		x = a; y = b;
	}
};

inline LF Dis(Point p1, Point p2)
{
	return sqrt(Sqr(p1.x - p2.x) + Sqr(p1.y - p2.y));
}

struct Circle
{
	Point o;
	LF r;
} C[MaxN], S[MaxN];

inline bool Cmp1(Circle c1, Circle c2)
{
	return c1.r < c2.r;
}

inline bool Cmp2(Circle c1, Circle c2)
{
	return c1.o.x - c1.r < c2.o.x - c2.r;
}

bool Del[MaxN];

struct Segment
{
	LF l, r;
} Seg[MaxN];

inline bool Cmp3(Segment s1, Segment s2)
{
	return s1.l < s2.l;
}

inline LF f(LF x)
{
	LF ret = 0.0, p, q, Hi;
	Top = 0;
	for (int i = Lc; i <= Rc; ++i)
	{
		if (x <= S[i].o.x - S[i].r || x >= S[i].o.x + S[i].r) continue;
		Hi = sqrt(Sqr(S[i].r) - Sqr(S[i].o.x - x));
		Seg[++Top].l = S[i].o.y - Hi; Seg[Top].r = S[i].o.y + Hi;
	}
	sort(Seg + 1, Seg + Top + 1, Cmp3);
	for (int i = 1, j; i <= Top; ++i)
	{
		p = Seg[i].l; q = Seg[i].r;
		for (j = i + 1; j <= Top; ++j)
		{
			if (Seg[j].l > q) break;
			if (Seg[j].r > q) q = Seg[j].r;
		}
		ret += q - p; i = j - 1;	
	}
	return ret;	
}

inline LF Simpson(LF l, LF r, LF fl, LF fmid, LF fr)
{
	return (fl + 4.0 * fmid + fr) * (r - l) / 6.0;
}

inline LF RSimpson(LF l, LF r, LF fl, LF fmid, LF fr)
{
	LF mid, p, q, x, y, z;
	mid = (l + r) / 2.0;
	p = f((l + mid) / 2.0); q = f((mid + r) / 2.0);
	x = Simpson(l, r, fl, fmid, fr);
	y = Simpson(l, mid, fl, p, fmid);
	z = Simpson(mid, r, fmid, q, fr);
	if (fabs(x - y - z) < Eps) return y + z;
	else return RSimpson(l, mid, fl, p, fmid) + RSimpson(mid, r, fmid, q, fr);
}

int main()
{
	scanf("%d", &n);
	int a, b, c;
	for (int i = 1; i <= n; ++i)
	{
		scanf("%d%d%d", &a, &b, &c);		
		C[i].o = Point((LF)a, (LF)b);
		C[i].r = (LF)c;
	}	
	sort(C + 1, C + n + 1, Cmp1);
	memset(Del, 0, sizeof(Del));
	for (int i = 1; i <= n; ++i)
		for (int j = i + 1; j <= n; ++j)
			if (Dis(C[i].o, C[j].o) <= C[j].r - C[i].r)
			{
				Del[i] = true;
				break;
			}
	Tot = 0;
	for (int i = 1; i <= n; ++i) 
		if (!Del[i]) S[++Tot] = C[i];
	sort(S + 1, S + Tot + 1, Cmp2);
	Ans = 0.0;
	for (int i = 1, j; i <= Tot; ++i)
	{
		Lc = i; Rc = i; Lx = S[i].o.x - S[i].r; Rx = S[i].o.x + S[i].r;
		for (j = i + 1; j <= Tot; ++j)
		{
			if (S[j].o.x - S[j].r > Rx) break;
			if (S[j].o.x + S[j].r > Rx) Rx = S[j].o.x + S[j].r;
		}
		Rc = j - 1; i = j - 1;
		Ans += RSimpson(Lx, Rx, f(Lx), f((Lx + Rx) / 2.0), f(Rx));
	}
	printf("%.3lf\n", Ans);
	return 0;
}

  

posted @ 2015-04-02 15:39  JoeFan  阅读(394)  评论(0编辑  收藏  举报