SPOJ CIRUT - CIRU2 (多个圆交,求交任意次的面积,模板题)
题意&思路:
给出n个圆
求恰好k个圆相交的面积,k属于1..n
先放个别人的代码。。。
我真是体会到了。。。软件工程这门课的重要性。。。
这代码真是烂得印象深刻。。。几何题全是面向过程?
circle和point 类写在一起。。。感觉所有糟糕的写法这份代码全都占了。。。
1/* ***********************************************
2Author :111qqz
3Created Time :2017年10月11日 星期三 19时53分30秒
4File Name :ciru.cpp
5************************************************ */
6
7#include <cstdio>
8#include <cstring>
9#include <iostream>
10#include <algorithm>
11#include <vector>
12#include <queue>
13#include <set>
14#include <map>
15#include <string>
16#include <cmath>
17#include <cstdlib>
18#include <ctime>
19#define PB push_back
20#define fst first
21#define sec second
22#define lson l,m,rt<<1
23#define rson m+1,r,rt<<1|1
24#define ms(a,x) memset(a,x,sizeof(a))
25#define pi pair < int ,int >
26#define MP make_pair
27
28using namespace std;
29
30typedef long long LL;
31typedef unsigned long long ULL;
32typedef vector <int> VI;
33const int INF = 0x3f3f3f3f;
34const double eps = 1e-10;
35const int MOD = 100000007;
36const int MAXN = 1E3+7;
37const double PI = acos(-1.0);
38#define sqr(x) ((x)*(x))
39const int N = 1010;
40double area[N];
41int n;
42
43int dcmp(double x)
44{
45 if (x < -eps) return -1;
46 else return x > eps;
47}
48
49struct cp
50{
51 double x, y, r, angle;
52 int d;
53 cp() {}
54 cp(double xx, double yy, double ang = 0, int t = 0)
55 {
56 x = xx;
57 y = yy;
58 angle = ang;
59 d = t;
60 }
61 void get()
62 {
63 scanf("%lf%lf%lf", &x, &y, &r);
64 d = 1;
65 }
66} cir[N], tp[N * 2];
67
68double dis(cp a, cp b)
69{
70 return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
71}
72
73double cross(cp p0, cp p1, cp p2)
74{
75 return (p1.x - p0.x) * (p2.y - p0.y) - (p1.y - p0.y) * (p2.x - p0.x);
76}
77
78int CirCrossCir(cp p1, double r1, cp p2, double r2, cp &cp1, cp &cp2)
79{
80 double mx = p2.x - p1.x, sx = p2.x + p1.x, mx2 = mx * mx;
81 double my = p2.y - p1.y, sy = p2.y + p1.y, my2 = my * my;
82 double sq = mx2 + my2, d = -(sq - sqr(r1 - r2)) * (sq - sqr(r1 + r2));
83 if (d + eps < 0) return 0;
84 if (d < eps) d = 0;
85 else d = sqrt(d);
86 double x = mx * ((r1 + r2) * (r1 - r2) + mx * sx) + sx * my2;
87 double y = my * ((r1 + r2) * (r1 - r2) + my * sy) + sy * mx2;
88 double dx = mx * d, dy = my * d;
89 sq *= 2;
90 cp1.x = (x - dy) / sq;
91 cp1.y = (y + dx) / sq;
92 cp2.x = (x + dy) / sq;
93 cp2.y = (y - dx) / sq;
94 if (d > eps) return 2;
95 else return 1;
96}
97
98bool circmp(const cp& u, const cp& v)
99{
100 return dcmp(u.r - v.r) < 0;
101}
102
103bool cmp(const cp& u, const cp& v)
104{
105 if (dcmp(u.angle - v.angle)) return u.angle < v.angle;
106 return u.d > v.d;
107}
108
109double calc(cp cir, cp cp1, cp cp2)
110{
111 double ans = (cp2.angle - cp1.angle) * sqr(cir.r)
112 - cross(cir, cp1, cp2) + cross(cp(0, 0), cp1, cp2);
113 return ans / 2;
114}
115
116void CirUnion(cp cir[], int n)
117{
118 cp cp1, cp2;
119 sort(cir, cir + n, circmp);
120 for (int i = 0; i < n; ++i)
121 for (int j = i + 1; j < n; ++j)
122 if (dcmp(dis(cir[i], cir[j]) + cir[i].r - cir[j].r) <= 0)
123 cir[i].d++;
124 for (int i = 0; i < n; ++i)
125 {
126 int tn = 0, cnt = 0;
127 for (int j = 0; j < n; ++j)
128 {
129 if (i == j) continue;
130 if (CirCrossCir(cir[i], cir[i].r, cir[j], cir[j].r,
131 cp2, cp1) < 2) continue;
132 cp1.angle = atan2(cp1.y - cir[i].y, cp1.x - cir[i].x);
133 cp2.angle = atan2(cp2.y - cir[i].y, cp2.x - cir[i].x);
134 cp1.d = 1;
135 tp[tn++] = cp1;
136 cp2.d = -1;
137 tp[tn++] = cp2;
138 if (dcmp(cp1.angle - cp2.angle) > 0) cnt++;
139 }
140 tp[tn++] = cp(cir[i].x - cir[i].r, cir[i].y, PI, -cnt);
141 tp[tn++] = cp(cir[i].x - cir[i].r, cir[i].y, -PI, cnt);
142 sort(tp, tp + tn, cmp);
143 int p, s = cir[i].d + tp[0].d;
144 for (int j = 1; j < tn; ++j)
145 {
146 p = s;
147 s += tp[j].d;
148 area[p] += calc(cir[i], tp[j - 1], tp[j]);
149 }
150 }
151}
152
153void solve()
154{
155 scanf("%d", &n);
156 for (int i = 0; i < n; ++i)
157 cir[i].get();
158 memset(area, 0, sizeof(area));
159 CirUnion(cir, n);
160 //去掉重复计算的
161 for (int i = 1; i <= n; ++i)
162 {
163 area[i] -= area[i + 1];
164 }
165 //area[i]为重叠了i次的面积
166 for ( int i = 1 ; i <= n ; i++) printf("[%d] = %.3f\n",i,area[i]+eps);
167 //tot 为总面积
168 //double tot = 0;
169 //for(int i=1; i<=n; i++) tot += area[i];
170 //printf("%f\n", tot);
171}
172
173int main()
174{
175 // freopen("./in.txt", "r", stdin);
176 solve();
177 return 0;
178}
打算改写一下。。。这代码实在是。。烂得看不下去了。。。
所以说。。。读别人代码。。。才能体会到代码风格的重要性啊。。。orz
重构了代码,感觉清爽了很多。。
1/* ***********************************************
2Author :111qqz
3Created Time :2017年10月11日 星期三 19时53分30秒
4File Name :ciru.circlep
5************************************************ */
6
7#include <cstdio>
8#include <cstring>
9#include <iostream>
10#include <algorithm>
11#include <vector>
12#include <queue>
13#include <set>
14#include <map>
15#include <string>
16#include <cmath>
17#include <cstdlib>
18#include <ctime>
19#define PB push_back
20#define fst first
21#define sec second
22#define lson l,m,rt<<1
23#define rson m+1,r,rt<<1|1
24#define ms(a,x) memset(a,x,sizeof(a))
25#define pi pair < int ,int >
26#define MP make_pair
27using namespace std;
28typedef long long LL;
29typedef unsigned long long ULL;
30typedef vector <int> VI;
31const int INF = 0x3f3f3f3f;
32const double eps = 1e-10;
33const int MAXN = 1E3+7;
34const double PI = acos(-1.0);
35#define sqr(x) ((x)*(x))
36const int N = 1010;
37double area[N];
38int n;
39
40int dblcmp(double d){ return d<-eps?-1:d>eps;}
41struct point
42{
43 double x,y;
44 double ang;
45 int d;
46 point(){}
47 point(double x,double y):x(x),y(y){}
48 point(double _x,double _y,double _ang,int _d)
49 {
50 x = _x;
51 y = _y;
52 ang = _ang;
53 d = _d;
54 }
55 void input(){scanf("%lf%lf",&x,&y);}
56 double angle(){ return atan2(y,x);}
57 point operator + (const point &rhs)const{ return point(x+rhs.x,y+rhs.y);}
58 point operator - (const point &rhs)const{ return point(x-rhs.x,y-rhs.y);}
59 point operator * (double t)const{ return point(t*x,t*y);}
60 point operator / (double t)const{ return point(x/t,y/t);}
61 double length() const { return sqrt(x*x+y*y);};
62 point unit()const { double l = length();return point(x/l,y/l); }
63}tp[N*2];
64double cross (const point a,point b){ return a.x*b.y-a.y*b.x ;}
65double dist(const point p1,point p2) { return (p1-p2).length();}
66struct circle
67{
68 point c;
69 double r;
70 int d;
71 void input()
72 {
73 c.input();
74 scanf("%lf",&r);
75 d = 1;
76 }
77 bool contain (const circle & cir)const{ return dblcmp(dist(cir.c,c)+cir.r-r)<=0;}
78 bool interect (const circle & cir)const{ return dblcmp(dist(cir.c,c)-cir.r-r)<0;}
79} cir[N];// tp[N * 2];
80
81double dis(point a, point b) {return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));}
82int CirCrossCir(circle cir1,circle cir2, point &p1, point &p2)
83{
84 point m = cir2.c-cir1.c;
85 point s = cir2.c+cir1.c;
86 point m2 = point(sqr(m.x),sqr(m.y));
87 double dis2 = m2.x + m2.y, d = -(dis2 - sqr(cir1.r - cir2.r)) * (dis2 - sqr(cir1.r + cir2.r));
88 if (d + eps < 0) return 0;
89 if (d < eps) d = 0;
90 else d = sqrt(d);
91 double x = m.x * ((cir1.r + cir2.r) * (cir1.r - cir2.r) + m.x * s.x) + s.x * m2.y;
92 double y = m.y * ((cir1.r+ cir2.r) * (cir1.r - cir2.r) + m.y * s.y) + s.y * m2.x;
93 point dp = m*d;
94 dis2 *= 2;
95 p1 = point (x-dp.y,y+dp.x)/dis2;
96 p2 = point (x+dp.y,y-dp.x)/dis2;
97 if (d > eps) return 2;
98 else return 1;
99}
100bool circmp(const circle& u, const circle& v)
101{
102 return dblcmp(u.r - v.r) < 0;
103}
104bool cmp(const point& u, const point& v)
105{
106 if (dblcmp(u.ang - v.ang)) return u.ang < v.ang;
107 return u.d > v.d;
108}
109
110double calc(circle cir, point p1, point p2)
111{
112 double ans = (p2.ang - p1.ang) * sqr(cir.r)
113 - cross ( (p1-cir.c),(p2-cir.c)) + cross( p1,p2);
114 return ans *0.5;
115}
116
117void CirUnion(circle cir[], int n)
118{
119 circle cir1, cir2;
120 point p1,p2;
121 sort(cir, cir + n, circmp);
122 for (int i = 0; i < n; ++i)
123 for (int j = i + 1; j < n; ++j)
124 if (cir[j].contain(cir[i]))
125 cir[i].d++;
126 for (int i = 0; i < n; ++i)
127 {
128 int tn = 0, cnt = 0;
129 for (int j = 0; j < n; ++j)
130 {
131 if (i == j) continue;
132 if (CirCrossCir(cir[i],cir[j],p2, p1) < 2) continue;
133 p1.ang = (p1-cir[i].c).angle();
134 p2.ang = (p2-cir[i].c).angle();
135 p1.d = 1;
136 tp[tn++] = p1;
137 p2.d = -1;
138 tp[tn++] = p2;
139 if (dblcmp(p1.ang - p2.ang) > 0) cnt++;
140 }
141 tp[tn++] = point(cir[i].c.x - cir[i].r, cir[i].c.y, PI, -cnt);
142 tp[tn++] = point(cir[i].c.x - cir[i].r, cir[i].c.y, -PI, cnt);
143 sort(tp, tp + tn, cmp);
144 int p, s = cir[i].d + tp[0].d;
145 for (int j = 1; j < tn; ++j)
146 {
147 p = s;
148 s += tp[j].d;
149 area[p] += calc(cir[i], tp[j - 1], tp[j]);
150 }
151 }
152}
153void solve()
154{
155 scanf("%d", &n);
156 for (int i = 0; i < n; ++i)
157 cir[i].input();
158 memset(area, 0, sizeof(area));
159 CirUnion(cir, n);
160 //去掉重复计算的
161 for (int i = 1; i <= n; ++i)
162 {
163 area[i] -= area[i + 1];
164 }
165 //area[i]为重叠了i次的面积
166 for ( int i = 1 ; i <= n ; i++) printf("[%d] = %.3f\n",i,area[i]+eps);
167 //tot 为总面积
168 //double tot = 0;
169 //for(int i=1; i<=n; i++) tot += area[i];
170 //printf("%f\n", tot);
171}
172
173int main()
174{
175 // freopen("./in.txt", "r", stdin);
176 solve();
177 return 0;
178}