思路:
小圆面是由小圆弧围成。那么找出每条小圆弧,如果小圆弧,在小圆弧中点上下左右进行微小位移的所得的点一定在一个小圆面内。
找到最后覆盖这个小点的圆一定是可见的。
圆上的点按照相邻依次排序的关键量为极角(0,2PI)
用中心点代替圆弧本身是否被圆覆盖
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 << " "; 137 } 138 return 0; 139 }