uva 2572 Viva Confetti

思路: 

小圆面是由小圆弧围成。那么找出每条小圆弧,如果小圆弧,在小圆弧中点上下左右进行微小位移的所得的点一定在一个小圆面内。

找到最后覆盖这个小点的圆一定是可见的。

圆上的点按照相邻依次排序的关键量为极角(0,2PI)

用中心点代替圆弧本身是否被圆覆盖

 

  1 #include<cstdio>
  2 #include<cmath>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<iostream>
  6 #include<memory.h>
  7 #include<cstdlib>
  8 #include<vector>
  9 #define clc(a,b) memset(a,b,sizeof(a))
 10 #define LL long long int
 11 #define up(i,x,y) for(i=x;i<=y;i++)
 12 #define w(a) while(a)
 13 using namespace std;
 14 const int inf=0x3f3f3f3f;
 15 const int N = 4010;
 16 const double eps = 5*1e-13;
 17 const double pi = acos(-1);
 18 
 19 int dcmp(double x)
 20 {
 21     if(fabs(x) < eps) return 0;
 22     else return x < 0 ? -1 : 1;
 23 }
 24 
 25 const double PI = acos(-1);
 26 const double TWO_PI = PI * 2;
 27 
 28 double NormalizeAngle(double rad, double center = PI)
 29 {
 30     return rad - TWO_PI * floor((rad + PI - center) / TWO_PI);
 31 }
 32 
 33 struct Point
 34 {
 35     double x, y;
 36     Point(double x=0, double y=0):x(x),y(y) { }
 37 };
 38 
 39 typedef Point Vector;
 40 
 41 Vector operator + (Vector A, Vector B)
 42 {
 43     return Vector(A.x+B.x, A.y+B.y);
 44 }
 45 Vector operator - (Point A, Point B)
 46 {
 47     return Vector(A.x-B.x, A.y-B.y);
 48 }
 49 Vector operator * (Vector A, double p)
 50 {
 51     return Vector(A.x*p, A.y*p);
 52 }
 53 Vector operator / (Vector A, double p)
 54 {
 55     return Vector(A.x/p, A.y/p);
 56 }
 57 
 58 double Dot(Vector A, Vector B)
 59 {
 60     return A.x*B.x + A.y*B.y;
 61 }
 62 double Length(Vector A)
 63 {
 64     return sqrt(Dot(A, A));
 65 }
 66 
 67 double angle(Vector v)
 68 {
 69     return atan2(v.y, v.x);
 70 }
 71 
 72 // 交点相对于圆1的极角保存在rad中
 73 void getCircleCircleIntersection(Point c1, double r1, Point c2, double r2, vector<double>& rad)
 74 {
 75     double d = Length(c1 - c2);
 76     if(dcmp(d) == 0) return; // 不管是内含还是重合,都不相交
 77     if(dcmp(r1 + r2 - d) < 0) return;
 78     if(dcmp(fabs(r1-r2) - d) > 0) return;
 79 
 80     double a = angle(c2 - c1);
 81     double da = acos((r1*r1 + d*d - r2*r2) / (2*r1*d));
 82     rad.push_back(NormalizeAngle(a-da));
 83     rad.push_back(NormalizeAngle(a+da));
 84 }
 85 
 86 const int maxn = 100 + 5;
 87 int n;
 88 Point center[maxn];
 89 double radius[maxn];
 90 bool vis[maxn];
 91 
 92 // 覆盖点p的最上层的圆
 93 int topmost(Point p)
 94 {
 95     for(int i = n-1; i >= 0; i--)
 96         if(Length(center[i]-p) < radius[i]) return i;
 97     return -1;
 98 }
 99 
100 int main()
101 {
102     while(cin >> n)
103     {
104         if(!n) break;
105         for(int i = 0; i < n; i++)
106         {
107             double x, y, r;
108             cin >> x >> y >> r;
109             center[i] = Point(x, y);
110             radius[i] = r;
111         }
112         memset(vis, 0, sizeof(vis));
113         for(int i = 0; i < n; i++)
114         {
115             // 考虑圆i被切割成的各个圆弧。把圆周当做区间来处理,起点是0,终点是2PI
116             vector<double> rad;
117             rad.push_back(0);
118             rad.push_back(PI*2);
119             for(int j = 0; j < n; j++)
120                 getCircleCircleIntersection(center[i], radius[i], center[j], radius[j], rad);
121             sort(rad.begin(), rad.end());
122 
123             for(int j = 0; j < rad.size(); j++)
124             {
125                 double mid = (rad[j] + rad[j+1]) / 2.0; // 圆弧中点相对于圆i圆心的极角
126                 for(int side = -1; side <= 1; side += 2)
127                 {
128                     double r2 = radius[i] - side*eps; // 往里面或者外面稍微一动一点点
129                     int t = topmost(Point(center[i].x + cos(mid)*r2, center[i].y + sin(mid)*r2));
130                     if(t >= 0) vis[t] = true;
131                 }
132             }
133         }
134         int ans = 0;
135         for(int i = 0; i < n; i++) if(vis[i]) ans++;
136         cout << ans << "\n";
137     }
138     return 0;
139 }
View Code

 

posted @ 2015-10-13 00:46  yyblues  阅读(218)  评论(0编辑  收藏  举报