多圆面积交模板

main函数中只要调用solve()就好了,solve函数中的n即代表n个圆,先输入n,再输入n个圆的圆心坐标和半径,直接在函数中输出多圆相交的公共面积

main函数中不用做什么,所有的东西都在solve完成了

[cpp]  view plain copy
  1. typedef long long LL;  
  2. typedef unsigned long long ULL;  
  3. typedef vector <int> VI;  
  4. const int INF = 0x3f3f3f3f;  
  5. const double eps = 1e-10;  
  6. const int MOD = 100000007;  
  7. const int MAXN = 1000010;  
  8. const double PI = acos(-1.0);  
  9. #define sqr(x) ((x)*(x))  
  10. const int N = 1010;  
  11. double area[N];  
  12. int n;  
  13.   
  14. int dcmp(double x)  
  15. {  
  16.     if (x < -eps) return -1;  
  17.     else return x > eps;  
  18. }  
  19.   
  20. struct cp  
  21. {  
  22.     double x, y, r, angle;  
  23.     int d;  
  24.     cp() {}  
  25.     cp(double xx, double yy, double ang = 0, int t = 0)  
  26.     {  
  27.         x = xx;  
  28.         y = yy;  
  29.         angle = ang;  
  30.         d = t;  
  31.     }  
  32.     void get()  
  33.     {  
  34.         scanf("%lf%lf%lf", &x, &y, &r);  
  35.         d = 1;  
  36.     }  
  37. } cir[N], tp[N * 2];  
  38.   
  39. double dis(cp a, cp b)  
  40. {  
  41.     return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));  
  42. }  
  43.   
  44. double cross(cp p0, cp p1, cp p2)  
  45. {  
  46.     return (p1.x - p0.x) * (p2.y - p0.y) - (p1.y - p0.y) * (p2.x - p0.x);  
  47. }  
  48.   
  49. int CirCrossCir(cp p1, double r1, cp p2, double r2, cp &cp1, cp &cp2)  
  50. {  
  51.     double mx = p2.x - p1.x, sx = p2.x + p1.x, mx2 = mx * mx;  
  52.     double my = p2.y - p1.y, sy = p2.y + p1.y, my2 = my * my;  
  53.     double sq = mx2 + my2, d = -(sq - sqr(r1 - r2)) * (sq - sqr(r1 + r2));  
  54.     if (d + eps < 0) return 0;  
  55.     if (d < eps) d = 0;  
  56.     else d = sqrt(d);  
  57.     double x = mx * ((r1 + r2) * (r1 - r2) + mx * sx) + sx * my2;  
  58.     double y = my * ((r1 + r2) * (r1 - r2) + my * sy) + sy * mx2;  
  59.     double dx = mx * d, dy = my * d;  
  60.     sq *= 2;  
  61.     cp1.x = (x - dy) / sq;  
  62.     cp1.y = (y + dx) / sq;  
  63.     cp2.x = (x + dy) / sq;  
  64.     cp2.y = (y - dx) / sq;  
  65.     if (d > eps) return 2;  
  66.     else return 1;  
  67. }  
  68.   
  69. bool circmp(const cp& u, const cp& v)  
  70. {  
  71.     return dcmp(u.r - v.r) < 0;  
  72. }  
  73.   
  74. bool cmp(const cp& u, const cp& v)  
  75. {  
  76.     if (dcmp(u.angle - v.angle)) return u.angle < v.angle;  
  77.     return u.d > v.d;  
  78. }  
  79.   
  80. double calc(cp cir, cp cp1, cp cp2)  
  81. {  
  82.     double ans = (cp2.angle - cp1.angle) * sqr(cir.r)  
  83.                  - cross(cir, cp1, cp2) + cross(cp(0, 0), cp1, cp2);  
  84.     return ans / 2;  
  85. }  
  86.   
  87. void CirUnion(cp cir[], int n)  
  88. {  
  89.     cp cp1, cp2;  
  90.     sort(cir, cir + n, circmp);  
  91.     for (int i = 0; i < n; ++i)  
  92.         for (int j = i + 1; j < n; ++j)  
  93.             if (dcmp(dis(cir[i], cir[j]) + cir[i].r - cir[j].r) <= 0)  
  94.                 cir[i].d++;  
  95.     for (int i = 0; i < n; ++i)  
  96.     {  
  97.         int tn = 0, cnt = 0;  
  98.         for (int j = 0; j < n; ++j)  
  99.         {  
  100.             if (i == j) continue;  
  101.             if (CirCrossCir(cir[i], cir[i].r, cir[j], cir[j].r,  
  102.                             cp2, cp1) < 2) continue;  
  103.             cp1.angle = atan2(cp1.y - cir[i].y, cp1.x - cir[i].x);  
  104.             cp2.angle = atan2(cp2.y - cir[i].y, cp2.x - cir[i].x);  
  105.             cp1.d = 1;  
  106.             tp[tn++] = cp1;  
  107.             cp2.d = -1;  
  108.             tp[tn++] = cp2;  
  109.             if (dcmp(cp1.angle - cp2.angle) > 0) cnt++;  
  110.         }  
  111.         tp[tn++] = cp(cir[i].x - cir[i].r, cir[i].y, PI, -cnt);  
  112.         tp[tn++] = cp(cir[i].x - cir[i].r, cir[i].y, -PI, cnt);  
  113.         sort(tp, tp + tn, cmp);  
  114.         int p, s = cir[i].d + tp[0].d;  
  115.         for (int j = 1; j < tn; ++j)  
  116.         {  
  117.             p = s;  
  118.             s += tp[j].d;  
  119.             area[p] += calc(cir[i], tp[j - 1], tp[j]);  
  120.         }  
  121.     }  
  122. }  
  123.   
  124. void solve()  
  125. {  
  126.     scanf("%d", &n);  
  127.     for (int i = 0; i < n; ++i)  
  128.         cir[i].get();  
  129.     memset(area, 0, sizeof(area));  
  130.     CirUnion(cir, n);  
  131.     //去掉重复计算的  
  132.     for (int i = 1; i <= n; ++i)  
  133.     {  
  134.         area[i] -= area[i + 1];  
  135.     }  
  136.     //area[i]为重叠了i次的面积  
  137.     //tot 为总面积  
  138.     double tot = 0;  
  139.     for(int i=1; i<=n; i++) tot += area[i];  
  140.     printf("%f\n", tot);  
  141. }  
  142.   
  143. int main()  
  144. {  
  145.     //freopen("input.txt", "r", stdin);  
  146.     return 0;  
  147. }  

你可能感兴趣的:(多圆面积交模板)