uva 1308 - Viva Confetti

这个题目的方法是将圆盘分成一个个圆环,然后判断这些圆环是否被上面的圆覆盖;

如果这个圆的圆周上的圆弧都被上面的覆盖,暂时把它标记为不可见;

然后如果他的头上有个圆,他有个圆弧可见,那么他自己本身可见,并且可以把这条圆弧下面的第一个圆重新标记为可见;

另外,圆弧可见还是不可见利用它的中点来进行判断;

  1 #include <cstdio>
  2 #include <cmath>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <vector>
  6 
  7 using namespace std;
  8 
  9 const int maxn = 100 + 10;
 10 const double eps = 1e-14;        //别开太大,样例数据就到达1e-11级别
 11 const double pi = acos(-1);
 12 
 13 int dcmp(double x)
 14 {
 15     return fabs(x) < eps ? 0 : (x > 0 ? 1 : -1);
 16 }
 17 
 18 struct Point
 19 {
 20     double x;
 21     double y;
 22 
 23     Point(double x = 0, double y = 0):x(x), y(y) {}
 24 
 25     bool operator < (const Point& e) const
 26     {
 27         return dcmp(x - e.x) < 0 || (dcmp(x - e.x) == 0 && dcmp(y - e.y) < 0);
 28     }
 29 
 30     bool operator == (const Point& e) const
 31     {
 32         return dcmp(x - e.x) == 0 && dcmp(y - e.y) == 0;
 33     }
 34 
 35     int read()
 36     {
 37         return scanf("%lf%lf", &x, &y);
 38     }
 39 };
 40 
 41 typedef Point Vector;
 42 
 43 Vector operator + (Point A, Point B)
 44 {
 45     return Vector(A.x + B.x, A.y + B.y);
 46 }
 47 
 48 Vector operator - (Point A, Point B)
 49 {
 50     return Vector(A.x - B.x, A.y - B.y);
 51 }
 52 
 53 Vector operator * (Point A, double p)
 54 {
 55     return Vector(A.x * p, A.y * p);
 56 }
 57 
 58 Vector operator / (Point A, double p)
 59 {
 60     return Vector(A.x / p, A.y / p);
 61 }
 62 
 63 struct Circle
 64 {
 65     Point c;
 66     double r;
 67 
 68     Circle() {}
 69     Circle(Point c, double r):c(c), r(r) {}
 70 
 71     int read()
 72     {
 73         return scanf("%lf%lf%lf", &c.x, &c.y, &r);
 74     }
 75 
 76     Point point(double a)
 77     {
 78         return Point(c.x + r * cos(a), c.y + r * sin(a));
 79     }
 80 };
 81 
 82 double Dot(Vector A, Vector B)
 83 {
 84     return A.x * B.x + A.y * B.y;
 85 }
 86 
 87 double Length(Vector A)
 88 {
 89     return sqrt(Dot(A, A));
 90 }
 91 
 92 double angle(Vector v)      //求向量的极角
 93 {
 94     return atan2(v.y, v.x);
 95 }
 96 
 97 bool PointInCircle(Point p, Circle C)       //判断点是否在圆内
 98 {
 99     double dist = Length(p - C.c);
100     if(dcmp(dist - C.r) > 0) return 0;      //这里我选择点在圆边上不算在圆内
101     else return 1;
102 }
103 
104 bool CircleInCircle(Circle A, Circle B)         //判断圆在圆内
105 {
106     double cdist = Length(A.c - B.c);
107     double rdiff = B.r - A.r;
108     if(dcmp(A.r - B.r) <= 0 && dcmp(cdist - rdiff) <= 0) return 1;      //包括重合,内切和内含的情况
109     return 0;
110 }
111 
112 int n;
113 Circle C[maxn];
114 bool vis[maxn];
115 vector<double> pointAng[maxn];
116 
117 int GetCircleCircleIntersection(int c1, int c2)       //求圆与圆的交点
118 {
119     Circle C1 = C[c1];
120     Circle C2 = C[c2];
121     double d = Length(C1.c - C2.c);
122     if(dcmp(d) == 0)
123     {
124         if(dcmp(C1.r - C2.r) == 0) return -1;       //两圆重合
125         return 0;       //同心圆但不重合
126     }
127     if(dcmp(C1.r + C2.r - d) < 0) return 0;     //外离
128     if(dcmp(fabs(C1.r - C2.r) - d) > 0) return 0;       //内含
129     double a = angle(C2.c - C1.c);
130     double da = acos((C1.r * C1.r + d * d - C2.r * C2.r) / (2 * C1.r * d));
131     Point p1 = C1.point(a + da);
132     Point p2 = C1.point(a - da);
133     if(p1 == p2) return 1;      //相切
134     pointAng[c1].push_back(a + da);     //相切的点不处理,只要相交的
135     pointAng[c1].push_back(a - da);
136     return 2;
137 }
138 
139 void init()
140 {
141     for(int i = 0; i < n; i++) pointAng[i].clear();
142     memset(vis, 0, sizeof(vis));
143 }
144 
145 void read()
146 {
147     for(int i = 0; i < n; i++) C[i].read();
148 }
149 
150 void solve()
151 {
152     for(int i = 0; i < n; i++)      //圆两两相交,得各圆交点集合
153         for(int j = 0; j < n; j++) if(i != j)
154                 GetCircleCircleIntersection(i, j);
155     for(int i = 0; i < n; i++)
156     {
157         sort(pointAng[i].begin(), pointAng[i].end());       //各圆交点按极角排序
158         vector<double>::iterator iter = unique(pointAng[i].begin(), pointAng[i].end());     //去重,可减少运行时间,不去重也能AC
159         pointAng[i].resize(distance(pointAng[i].begin(), iter));
160     }
161     for(int i = 0; i < n; i++)      //判断第i个圆上的弧
162     {
163         int sz = pointAng[i].size();
164         if(!sz)         //此圆不与其他圆相交
165         {
166             bool ok = 1;
167             for(int k = i+1; k < n; k++) if(CircleInCircle(C[i], C[k]))         //判上面是否有圆把它覆盖掉
168                 {
169                     ok = 0;
170                     break;
171                 }
172             if(ok) vis[i] = 1;
173         }
174         else
175         {
176             pointAng[i].push_back(pointAng[i][0]);
177             for(int j = 0; j < sz; j++)         //第i个圆上的第j条弧
178             {
179                 bool ok = 1;
180                 Point pm = C[i].point((pointAng[i][j] + pointAng[i][j+1]) / 2);     //取弧的中点
181                 for(int k = i+1; k < n; k++) if(PointInCircle(pm, C[k]))
182                     {
183                         ok = 0;
184                         break;
185                     }
186                 if(ok)
187                 {
188                     vis[i] = 1;
189                     for(int u = i-1; u >= 0; u--)if(PointInCircle(pm, C[u]))        //把这段圆弧下的圆设为可见
190                         {
191                             vis[u] = 1;
192                             break;
193                         }
194                 }
195             }
196         }
197     }
198     int ret = 0;
199     for(int i = 0; i < n; i++) if(vis[i]) ret++;
200     printf("%d\n", ret);
201 }
202 
203 int main()
204 {
205     while(scanf("%d", &n) == 1 && n)
206     {
207         init();
208         read();
209         solve();
210     }
211     return 0;
212 }
View Code

 

posted @ 2013-11-04 15:04  Yours1103  阅读(276)  评论(0编辑  收藏  举报