zju2589 不重合的n个圆形成的区域
1
/*
2 * SOUR:zju2589
3 * ALGO:computational geomtry 计算平面上不重合的n个圆形成的区域
4 * 基本的方法,如图所示,将所有圆之间的交点作为点,将在同一个圆上的所有交点之间的弧作
5 * 为边建立一张有向图,之后可以利用平面图的欧拉定理
6 * V - E + F = 2
7 * 由于V已知,E已知,F就可以求出来了。
8 * 由于欧拉定理是对一张无向连通图成立的,如果图有多个连通块的时候需要对欧拉定理做一些
9 * 修改。由于多个有向图的面共享最外边的面,所以设联通块的个数为n
10 * V - E + F = 2 * n , 但是需要减去n个联通块共享的最大平面
11 * 所以 F = n + 1 + E - V;
12 * DATE: 2010年 07月 08日 星期四 14:49:41 CST
13 * COMM:5
14 * */
15 const int N = 64 ;
16 const double eps = 1e - 8 ;
17 int n, vis[N], g[N][N];
18 double r[N];
19 struct point_t {
20 double x, y;
21 point_t(){}
22 point_t( double a, double b){x = a, y = b;}
23 }c[N];
24
25 int dcmp( double x) { return (x > eps) - (x < - eps);}
26 bool operator < (point_t a,point_t b)
27 {
28 if (dcmp(a.x - b.x)) {
29 return a.x < b.x;
30 }
31 return dcmp(a.y - b.y) < 0 ;
32 }
33
34 point_t operator + (point_t a, point_t b) { return point_t(a.x + b.x, a.y + b.y);}
35 point_t operator - (point_t a, point_t b) { return point_t(a.x - b.x, a.y - b.y);}
36 double dist(point_t a, point_t b) { return hypot(a.x - b.x, a.y - b.y);}
37 double sqr( double x) { return x * x;}
38 point_t normal(point_t a) { return point_t(a.x / hypot(a.x, a.y), a.y / hypot(a.x, a.y));}
39 point_t scale(point_t a, double fac) { return point_t(a.x * fac, a.y * fac);}
40 bool intersect(point_t c1, double r1, point_t c2, double r2, point_t & a, point_t & b)
41 {
42 double d = dist(c1, c2);
43 if (d < fabs(r1 - r2) - eps || d > r1 + r2 + eps) {
44 return false ;
45 }
46 double len = (sqr(r1) - sqr(r2) + sqr(d)) / 2.0 / d;
47 double h = sqrt(sqr(r1) - sqr(len));
48 point_t t = normal(c2 - c1);
49 point_t p = c1 + scale(t, len);
50 point_t v = scale(point_t( - t.y, t.x), h);
51 a = p + v, b = p - v;
52 return true ;
53 }
54
55 void init()
56 {
57 int i;
58 memset(g, 0 , sizeof (g));
59 memset(vis, 0 , sizeof (vis));
60 for (i = 0 ;i < n;i ++ ) {
61 g[i][i] = 1 ;
62 }
63 }
64
65 int main()
66 {
67 int testcase, i, j, k;
68 scanf( " %d " , & testcase);
69 while (testcase -- ) {
70 scanf( " %d " , & n);
71 set < point_t > allpoint, p[ 64 ];
72 for (i = 0 ;i < n;i ++ ) {
73 scanf( " %lf %lf %lf " , & c[i].x, & c[i].y, & r[i]);
74 }
75 init();
76 for (i = 0 ;i < n;i ++ ) {
77 for (j = i + 1 ;j < n;j ++ ) {
78 point_t a, b;
79 if (intersect(c[i], r[i], c[j], r[j], a, b)) {
80 allpoint.insert(a), allpoint.insert(b);
81 p[i].insert(a), p[i].insert(b);
82 p[j].insert(a), p[j].insert(b);
83 g[i][j] = g[j][i] = 1 ;
84 }
85 }
86 }
87 for (k = 0 ;k < n;k ++ ) {
88 for (i = 0 ;i < n;i ++ ) {
89 for (j = 0 ;j < n;j ++ ) {
90 g[i][j] |= g[i][k] & g[k][j];
91 }
92 }
93 }
94 int f = 1 ;
95 for (i = 0 ;i < n;i ++ ) {
96 f += p[i].size();
97 if ( ! vis[i]) {
98 f += 1 ;
99 for (j = 0 ;j < n;j ++ ) {
100 vis[j] |= g[i][j];
101 }
102 }
103 }
104 f -= allpoint.size();
105 printf( " %d\n " , f);
106 }
107 return 0 ;
108 }
109
110
2 * SOUR:zju2589
3 * ALGO:computational geomtry 计算平面上不重合的n个圆形成的区域
4 * 基本的方法,如图所示,将所有圆之间的交点作为点,将在同一个圆上的所有交点之间的弧作
5 * 为边建立一张有向图,之后可以利用平面图的欧拉定理
6 * V - E + F = 2
7 * 由于V已知,E已知,F就可以求出来了。
8 * 由于欧拉定理是对一张无向连通图成立的,如果图有多个连通块的时候需要对欧拉定理做一些
9 * 修改。由于多个有向图的面共享最外边的面,所以设联通块的个数为n
10 * V - E + F = 2 * n , 但是需要减去n个联通块共享的最大平面
11 * 所以 F = n + 1 + E - V;
12 * DATE: 2010年 07月 08日 星期四 14:49:41 CST
13 * COMM:5
14 * */
15 const int N = 64 ;
16 const double eps = 1e - 8 ;
17 int n, vis[N], g[N][N];
18 double r[N];
19 struct point_t {
20 double x, y;
21 point_t(){}
22 point_t( double a, double b){x = a, y = b;}
23 }c[N];
24
25 int dcmp( double x) { return (x > eps) - (x < - eps);}
26 bool operator < (point_t a,point_t b)
27 {
28 if (dcmp(a.x - b.x)) {
29 return a.x < b.x;
30 }
31 return dcmp(a.y - b.y) < 0 ;
32 }
33
34 point_t operator + (point_t a, point_t b) { return point_t(a.x + b.x, a.y + b.y);}
35 point_t operator - (point_t a, point_t b) { return point_t(a.x - b.x, a.y - b.y);}
36 double dist(point_t a, point_t b) { return hypot(a.x - b.x, a.y - b.y);}
37 double sqr( double x) { return x * x;}
38 point_t normal(point_t a) { return point_t(a.x / hypot(a.x, a.y), a.y / hypot(a.x, a.y));}
39 point_t scale(point_t a, double fac) { return point_t(a.x * fac, a.y * fac);}
40 bool intersect(point_t c1, double r1, point_t c2, double r2, point_t & a, point_t & b)
41 {
42 double d = dist(c1, c2);
43 if (d < fabs(r1 - r2) - eps || d > r1 + r2 + eps) {
44 return false ;
45 }
46 double len = (sqr(r1) - sqr(r2) + sqr(d)) / 2.0 / d;
47 double h = sqrt(sqr(r1) - sqr(len));
48 point_t t = normal(c2 - c1);
49 point_t p = c1 + scale(t, len);
50 point_t v = scale(point_t( - t.y, t.x), h);
51 a = p + v, b = p - v;
52 return true ;
53 }
54
55 void init()
56 {
57 int i;
58 memset(g, 0 , sizeof (g));
59 memset(vis, 0 , sizeof (vis));
60 for (i = 0 ;i < n;i ++ ) {
61 g[i][i] = 1 ;
62 }
63 }
64
65 int main()
66 {
67 int testcase, i, j, k;
68 scanf( " %d " , & testcase);
69 while (testcase -- ) {
70 scanf( " %d " , & n);
71 set < point_t > allpoint, p[ 64 ];
72 for (i = 0 ;i < n;i ++ ) {
73 scanf( " %lf %lf %lf " , & c[i].x, & c[i].y, & r[i]);
74 }
75 init();
76 for (i = 0 ;i < n;i ++ ) {
77 for (j = i + 1 ;j < n;j ++ ) {
78 point_t a, b;
79 if (intersect(c[i], r[i], c[j], r[j], a, b)) {
80 allpoint.insert(a), allpoint.insert(b);
81 p[i].insert(a), p[i].insert(b);
82 p[j].insert(a), p[j].insert(b);
83 g[i][j] = g[j][i] = 1 ;
84 }
85 }
86 }
87 for (k = 0 ;k < n;k ++ ) {
88 for (i = 0 ;i < n;i ++ ) {
89 for (j = 0 ;j < n;j ++ ) {
90 g[i][j] |= g[i][k] & g[k][j];
91 }
92 }
93 }
94 int f = 1 ;
95 for (i = 0 ;i < n;i ++ ) {
96 f += p[i].size();
97 if ( ! vis[i]) {
98 f += 1 ;
99 for (j = 0 ;j < n;j ++ ) {
100 vis[j] |= g[i][j];
101 }
102 }
103 }
104 f -= allpoint.size();
105 printf( " %d\n " , f);
106 }
107 return 0 ;
108 }
109
110