SPOJ CIRU The area of the union of circles (计算几何)

题意:求 m 个圆的并的面积。

析:就是一个板子题,还有要注意圆的半径为0的情况。

代码如下:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
#include <cmath>
#include <stack>
#include <sstream>
#define debug() puts("++++");
#define gcd(a, b) __gcd(a, b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define freopenr freopen("in.txt", "r", stdin)
#define freopenw freopen("out.txt", "w", stdout)
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<double, int> P;
const int INF = 0x3f3f3f3f;
const double inf = 0x3f3f3f3f3f3f;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int maxn = 1e4 + 10;
const int mod = 1e6;
const int dr[] = {-1, 0, 1, 0};
const int dc[] = {0, 1, 0, -1};
const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
int n, m;
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
inline bool is_in(int r, int c){
  return r >= 0 && r < n && c >= 0 && c < m;
}

int dcmp(double x){
  if(fabs(x) < eps)  return 0;
  if(x > 0)  return 1;
  return -1;
}
double sqr(double x){ return x * x; }

struct Point{
  double x, y;
  Point(){ }
  Point(double a, double b) : x(a), y(b) { }
  void input(){
    scanf("%lf %lf", &x, &y);
  }
  friend Point operator + (const Point &a, const Point &b){
    return Point(a.x + b.x, a.y + b.y);
  }
  friend Point operator - (const Point &a, const Point &b){
    return Point(a.x - b.x, a.y - b.y);
  }
  friend bool operator == (const Point &a, const Point &b){
    return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
  }
  friend Point operator * (const Point &a, const double &b){
    return Point(a.x * b, a.y * b);
  }
  friend Point operator * (const double &b, const Point &a){
    return Point(a.x * b, a.y * b);
  }
  friend Point operator / (const Point &a, const double &b){
    return Point(a.x / b, a.y / b);
  }
  double norm(){
    return sqrt(sqr(x) + sqr(y));
  }
};
double cross(const Point &a, const Point &b){
  return a.x * b.y - a.y * b.x;
}
struct Circle{
  Point p;
  double r;
  bool operator < (const Circle &o) const{
    if(dcmp(r-o.r) != 0)  return dcmp(r-o.r) == -1;
    if(dcmp(p.x-o.p.x) != 0)  return dcmp(p.x - o.p.x) == -1;
    return dcmp(p.y - o.p.y) == -1;
  }
  bool operator == (const Circle &o) const{
    return dcmp(r - o.r) == 0 && dcmp(p.x - o.p.x) == 0 && dcmp(p.y - o.p.y) == 0;
  }
};
Point rotate(const Point &p, double cost, double sint){
  double x = p.x, y = p.y;
  return Point(x*cost - y*sint, x*sint + y*cost);
}

pair<Point, Point> crossPoint(Point ap, double ar, Point bp, double br){
  double d = (ap - bp).norm();
  double cost = (ar*ar + d*d - br*br) / (2.0*ar*d);
  double sint = sqrt(1.0 - cost*cost);
  Point v = (bp - ap) / (bp - ap).norm() * ar;
  return make_pair(ap+rotate(v, cost, -sint), ap+rotate(v,  cost, sint));
}

pair<Point, Point> crossPoint(const Circle &a, const Circle &b){
  return crossPoint(a.p, a.r, b.p, b.r);
}
Circle c[maxn], tc[maxn];
#include<complex>
struct Node{
  Point p;
  double a;
  int d;
  Node(const Point &pp, double aa, int dd) : p(pp), a(aa), d(dd) { }
  bool operator < (const Node &o) const{
    return a < o.a;
  }
};
double arg(Point p){
  return arg(complex<double> (p.x, p.y));
}

double solve(){
  sort(tc, tc + m);
  m = unique(tc, tc + m) - tc;
  n = 0;
  for(int i = m-1; i >= 0; --i){
    bool ok = true;
    for(int j = i+1; j < m; ++j){
      double d = (tc[i].p - tc[j].p).norm();
      if(dcmp(d - abs(tc[i].r - tc[j].r)) <= 0){
        ok = false;  break;
      }
    }
    if(ok)  c[n++] = tc[i];
  }
  double ans = 0.0;
  for(int i = 0; i < n; ++i){
    vector<Node> event;
    Point boundary = c[i].p + Point(-c[i].r, 0);
    event.push_back(Node(boundary, -PI, 0));
    event.push_back(Node(boundary, PI, 0));
    for(int j = 0; j < n; ++j){
      if(i == j)  continue;
      double d = (c[i].p - c[j].p).norm();
      if(dcmp(d - (c[i].r + c[j].r)) < 0){
        pair<Point, Point> ret = crossPoint(c[i], c[j]);
        double x = arg(ret.first - c[i].p);
        double y = arg(ret.second - c[i].p);
        if(dcmp(x - y) > 0){
          event.push_back(Node(ret.first, x, 1));
          event.push_back(Node(boundary, PI, -1));
          event.push_back(Node(boundary, -PI, 1));
          event.push_back(Node(ret.second, y, -1));
        }
        else{
          event.push_back(Node(ret.first, x, 1));
          event.push_back(Node(ret.second, y, -1));
        }
      }
    }
    sort(event.begin(), event.end());
    int sum = event[0].d;
    for(int j = 1; j < event.size(); ++j){
      if(sum == 0){
        ans += cross(event[j-1].p, event[j].p) / 2.0;
        double x = event[j-1].a;
        double y = event[j].a;
        double area = c[i].r * c[i].r * (y-x) / 2.0;
        Point v1 = event[j-1].p - c[i].p;
        Point v2 = event[j].p - c[i].p;
        area -= cross(v1, v2) / 2.0;
        ans += area;
      }
      sum += event[j].d;
    }
  }
  return ans;
}

int main(){
  while(scanf("%d", &n) == 1){
    m = 0;
    for(int i = 0; i < n; ++i){
      tc[m].p.input();
      scanf("%lf", &tc[m].r);
      if(dcmp(tc[m].r) <= 0)  continue;
      ++m;
    }
    printf("%.3f\n", solve());
  }
  return 0;
}
时间: 2024-10-22 03:12:12

SPOJ CIRU The area of the union of circles (计算几何)的相关文章

SPOJ CIRU The area of the union of circles

You are given N circles and expected to calculate the area of the union of the circles ! Input The first line is one integer n indicates the number of the circles. (1 <= n <= 1000) Then follows n lines every line has three integers Xi Yi Ri indicate

SPOJ CIRU The area of the union of circles ——Simpson积分

[题目分析] 圆的面积并. 直接Simpson积分,(但是有计算几何的解法,留着flag). simpson积分,如果圆出现了不连续的情况,是很容易出事情的.(脑补一下) 但是没有什么办法,本来就是一种取巧的做法,还能指望这暴力积分做什么. [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include &l

The area of the union of circles

#include<stdio.h> #include<math.h> #include<algorithm> using namespace std; const double eps=1e-8; const double PI=acos(-1.0); struct Circle{ double x,y,r; Circle(){} Circle(double xx,double yy){x=xx;y=yy;} }; struct Node{//入点+1,可以表示覆盖了多

SPOJ CIRU SPOJ VCIRCLE 圆的面积并问题

SPOJ VCIRCLE SPOJ CIRU 两道题都是给出若干圆 就面积并,数据规模和精度要求不同. 求圆面积并有两种常见的方法,一种是Simpson积分,另一种是几何法. 在这里给出几何方法. PS.以下算法基于正方向为逆时针 考虑上图中的蓝色圆,绿色的圆和蓝色的圆交于 A,B 2个交点 ,我们在逆时针系下考虑,那么 可以知道 对于蓝色的圆,它对应的某个 角度区间被覆盖了 假设 区间为 [A, B], 并且角度是按照 圆心到交点的 向量的 极角来定义 (为了方便,我一般都把角度转化到 [0,

【转】[专题学习][计算几何]

原文地址:http://www.cnblogs.com/ch3656468/archive/2011/03/02/1969303.html 基本的叉积.点积和凸包等东西就不多说什么了,网上一搜一大堆,切一些题目基本熟悉了就差不多了. 一些基本的题目可以自己搜索,比如这个blog:http://blog.sina.com.cn/s/blog_49c5866c0100f3om.html 接下来,研究了半平面交,思想方法看07年朱泽园的国家队论文,模板代码参考自我校大牛韬哥: http://www.o

POJ 1654 Area 计算几何

#include<stdio.h> #include<string.h> #include<iostream> #include<math.h> using namespace std; int dx[10]={0,1,1,1,0,0,0,-1,-1,-1}; int dy[10]={0,-1,0,1,-1,0,1,-1,0,1}; char s[1000010]; __int64 area,x,y,px,py; int main() { int sum,t

The Inclusion-Exclusion Principle

The Inclusion-Exclusion Principle The inclusion-exclusion principle is an important combinatorial way to compute the size of a set or the probability of complex events. It relates the sizes of individual sets with their union. Statement The verbal fo

LeetCode解题思路:595. Big Countries

There is a table World +-----------------+------------+------------+--------------+---------------+ | name | continent | area | population | gdp | +-----------------+------------+------------+--------------+---------------+ | Afghanistan | Asia | 652

poj 1151 Atlantis

Atlantis http://poj.org/problem?id=1151 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 22662   Accepted: 8478 Description There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts