zoukankan      html  css  js  c++  java
  • [BZOJ2178]圆的面积并

    [BZOJ2178]圆的面积并

    试题描述

    给出 (N) 个圆,求其面积并

    输入

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

    输出

    面积并,保留三位小数

    输入示例 & 输出示例

    数据规模及约定

    见“输入

    题解

    裸的 Simpson 积分,可以用来解决一般的连续函数的积分。

    Simpson 积分是这样一个式子

    [int_l^r f(x) mathrm{d} x approx frac{1}{6}(r-l)(f(l)+f(r)+4f(frac{l+r}{2})) ]

    对于 (2) 次及以下的函数上面的式子求出来的是精确值。

    无聊的话可以证一下,令 (f(x) = ax^2 + bx + c)

    egin{aligned}
    int_l^r f(x) mathrm{d} x
    & = int_l^r (ax^2 + bx + c) mathrm{d}x \
    & = left( frac{1}{3} ar^3 + frac{1}{2} br^2 + cr ight) - left( frac{1}{3} al^3 + frac{1}{2} bl^2 + cl ight) \
    & = frac{1}{3} a (r-l)(r^2 + lr + l^2) + frac{1}{2} b (r-l)(r+l) + c(r-l) \
    & = frac{1}{6} (r-l) ( 2ar^2 + 2alr + 2al^2 + 3br + 3bl + 6c ) \
    & = frac{1}{6} (r-l) left[ (ar^2 + br + c) + (al^2 + bl + c) + 4a left( frac{r}{2} ight)^2 + 4aleft( frac{l}{2} ight)^2 + 4bleft( frac{r}{2} ight) + 4bleft( frac{l}{2} ight) + 4c ight] \
    & = frac{1}{6} (r-l) left[ f(r) + f(l) + 4f left( frac{l+r}{2} ight) ight]
    end{aligned}

    对于这道题,想象一条竖直扫描线从左到右扫过整个图形,那么答案其实就是对“直线在图形内部的长度”进行积分,套用上面的公式就可以得出大致的答案了;为了提高精度,我们可以进行分治,对于横坐标在 ([l, r]) 内的部分计算一下 ([l, r]) 的答案,看和 ([l, m])([m, r])(m = frac{l + r}{2}))的答案加起来是否相差很小,如果不够小则继续分治直接求 ([l, m])([m, r]) 的和。

    如何求出“在图形内部的长度”呢?注意到每个圆能转化成这条直线上的一个区间,最后就相当于求几个区间的并。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    #define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
    #define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)
     
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
     
    #define maxn 1010
     
    const double eps = 1e-13;
    struct Vec {
    	double x, y;
    	Vec() {}
    	Vec(double _, double __): x(_), y(__) {}
    	Vec operator - (const Vec& t) const { return Vec(x - t.x, y - t.y); }
    	double len() { return sqrt(x * x + y * y); }
    };
    struct Circle {
    	Vec p; double r;
    	Circle() {}
    	Circle(double _1, double _2, double _3): p(Vec(_1, _2)), r(_3) {}
    } inc[maxn], cs[maxn];
    int n;
    bool del[maxn];
     
    struct Line {
    	double l, r;
    	Line() {}
    	Line(double _, double __): l(_), r(__) {}
    	bool operator < (const Line& t) const { return l != t.l ? l < t.l : r > t.r; }
    } ls[maxn];
    int cl;
     
    double calcL(double x) {
    	cl = 0;
    	rep(i, 1, n) {
    		double d = abs(x - cs[i].p.x);
    		if(d >= cs[i].r) continue;
    		double h = sqrt(cs[i].r * cs[i].r - d * d);
    		ls[++cl] = Line(cs[i].p.y - h, cs[i].p.y + h);
    	}
    	if(!cl) return 0.0;
    	sort(ls + 1, ls + cl + 1);
    	double nl = ls[1].l, nr = ls[1].r, sum = 0;
    	rep(i, 2, cl) if(ls[i].l > nr) {
    		sum += nr - nl;
    		nl = ls[i].l; nr = ls[i].r;
    	}
    	else nr = max(nr, ls[i].r);
    	return sum + nr - nl;
    }
    double solve(double l, double r, double lLen, double mLen, double rLen) {
    	double mid = (l + r) * 0.5, lmLen = calcL((l + mid) * 0.5), rmLen = calcL((mid + r) * 0.5), S, lS, rS;
    	S = (r - l) * (lLen + rLen + 4.0 * mLen) / 6.0;
    	lS = (mid - l) * (lLen + mLen + 4.0 * lmLen) / 6.0;
    	rS = (r - mid) * (mLen + rLen + 4.0 * rmLen) / 6.0;
    	if(abs(lS + rS - S) < eps) return S;
    	return solve(l, mid, lLen, lmLen, mLen) + solve(mid, r, mLen, rmLen, rLen);
    }
     
    int main() {
    	double L = 10000, R = -10000;
    	n = read();
    	rep(i, 1, n) {
    		double x = read(), y = read(), r = read();
    		inc[i] = Circle(x, y, r);
    		L = min(L, x - r); R = max(R, x + r);
    	}
    	rep(i, 1, n)
    		rep(j, 1, n) if(inc[i].r > inc[j].r && (inc[i].p - inc[j].p).len() + inc[j].r <= inc[i].r) del[j] = 1;
    	int nn = 0;
    	rep(i, 1, n) if(!del[i]) cs[++nn] = inc[i];
    	n = nn;
    	 
    	printf("%.3lf
    ", solve(L, R, 0, calcL((L + R) * 0.5), 0));
    	 
    	return 0;
    }
    
  • 相关阅读:
    使用集合组织相关数据
    引用类型传递 ListView展示数据
    关于ArrayList线程安全解决方案
    Java异常错误的面试题及答案
    希尔排序
    Struts2的简单认识
    新闻发布系统
    了解vo pojo javabean dto
    Spring MVC 笔记及简单了解
    jsp的九大内置对象
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/8542079.html
Copyright © 2011-2022 走看看