首页 > 代码库 > ZOJ 1696 Viva Confetti 计算几何

ZOJ 1696 Viva Confetti 计算几何


计算几何:按顺序给n个圆覆盖,问最后可以有几个圆被看见。。。

对每个圆求和其他圆的交点,每两个交点之间就是可能被看到的圆弧,取圆弧的中点,往外扩展一点或者往里缩一点,从上往下判断有没有圆可以盖住这个点,能盖住这个点的最上面的圆一定是可见的


Viva Confetti

Time Limit: 2 Seconds      Memory Limit: 65536 KB

Do you know confetti? They are small discs of colored paper, and people throw them around during parties or festivals. Since people throw lots of confetti, they may end up stacked one on another, so there may be hidden ones underneath.

A handful of various sized confetti have been dropped on a table. Given their positions and sizes, can you tell us how many of them you can see?

The following figure represents the disc configuration for the first sample input, where the bottom disc is still visible.


Input

The input is composed of a number of configurations of the following form.

n
x1 y1 r1
x2 y2 r2
. . .
xn yn rn

The first line in a configuration is the number of discs in the configuration (a positive integer not more than 100), followed by one line descriptions of each disc: coordinates of its center and radius, expressed as real numbers in the decimal notation, with up to 12 digits after the decimal point. The imprecision margin is 5*10^-13. That is, it is guaranteed that variations of less than 5*10^-13 on input values do not change which discs are visible. Coordinates of all points contained in discs are between -10 and 10.

Confetti are listed in their stacking order, x1 y1 r1 being the bottom one and xn yn rn the top one. You are observing from the top.

The end of the input is marked by a zero on a single line.


Output

For each configuration you should output the number of visible confetti on a single line.


Sample Input

3
0 0 0.5
-0.9 0 1.00000000001
0.9 9 1.00000000001
5
0 1 0.5
1 1 1.00000000001
0 2 1.00000000001
-1 1 1.00000000001
0 -0.00001 1.00000000001
5
0 1 0.5
1 1 1.00000000001
0 2 1.00000000001
-1 1 1.00000000001
0 0 1.00000000001
2
0 0 1.0000001
0 0 1
2
0 0 1
0.00000001 0 1
0


Sample Output

3
5
4
2
2


Source: Asia 2002, Kanazawa (Japan)
Submit    Status


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

using namespace std;

const double eps=5*(1e-13);
const double pi=acos(-1.0);

int n;

struct Point
{
  double x,y;
  Point(){}
  Point(double _x,double _y):x(_x),y(_y){}
};

struct Circle
{
  Point c;
  double r;
  Circle(){}
  Circle(Point _c,double _r):c(_c),r(_r){}
  Point point(double x) {return Point(c.x+cos(x)*r,c.y+sin(x)*r);}
};

double normal(double x)
{
  return x-floor(x/(2*pi))*2*pi;
}

double dcmp(double x)
{
  if(fabs(x)<=eps) return 0;
  return (x<0)?-1:1;
}

double DIST(Point a,Point b)
{
  return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

Circle C[200];
double a[1000];
int tot=0;
bool flag[110];

void check(Point x)
{
  for(int i=n-1;i>=0;i--)
    {
      double d=DIST(x,C[i].c);
      if(dcmp(d-C[i].r)<0)
        {
          flag[i]=true; break;
        }
    }
}

int main()
{
  while(scanf("%d",&n)!=EOF&&n)
    {
      memset(flag,0,sizeof(flag));
      for(int i=0;i<n;i++)
        {
          double x,y,z;
          scanf("%lf%lf%lf",&x,&y,&z);
          C[i]=Circle(Point(x,y),z);
        }

      for(int i=0;i<n;i++)
        {
          tot=0;
          for(int j=0;j<n;j++)
            {
              if(i==j) continue;
              double dist=DIST(C[i].c,C[j].c);
              double ri=C[i].r,rj=C[j].r;
              if(dcmp(dist-ri-rj)>=0||dcmp(dist-fabs(ri-rj))<=0) continue;
              double t=atan2(C[j].c.y-C[i].c.y,C[j].c.x-C[i].c.x);
              double dt= acos((ri*ri+dist*dist-rj*rj)/(2.*ri*dist));
              a[tot++]=normal(t+dt); a[tot++]=normal(t-dt);
            }
          a[tot++]=0;a[tot++]=2*pi;
          sort(a,a+tot);
          tot=unique(a,a+tot)-a;
          for(int j=0;j<tot-1;j++)
            {
              double u=(a[j]+a[j+1])/2;
              double r1=C[i].r+eps,r2=C[i].r-eps;
              Point p1=Point(C[i].c.x+r1*cos(u),C[i].c.y+r1*sin(u));
              Point p2=Point(C[i].c.x+r2*cos(u),C[i].c.y+r2*sin(u));
              check(p1); check(p2);
            }
        }
      int ans=0;
      for(int i=0;i<n;i++)
        if(flag[i]) ans++;
      printf("%d\n",ans);
    }
  return 0;
}



ZOJ 1696 Viva Confetti 计算几何