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}