这两天算是整个浑浑噩噩的过了吧,感觉过的头脑甚是不清晰。晚上看到群信息有人在讨论woj,于是上去随便翻开了第一页,发现这个题没有做。一看分数是1的,以为是当初看到的简单题没有做,结果一看题目,求圆的面积并,并不是很简单。
关于圆的面积并,之前知道一个做法,也在区域赛的时候准备了模版,但从来没有真正写过这个代码,左右无事,就把这个代码写出来了。
这里用的是一个很不错的算法,关于算法请参考:http://wenku.baidu.com/view/2d2e730979563c1ec5da719c.html
这篇文章当中给出来算法的pascal代码,这里我用C++写了一遍,顺便用woj 1097做了测试。
/* * Author: stormdpzh * Created Time: 2013/4/4 22:44:20 * File Name: woj_1097.cpp */ #include <iostream> #include <cstdio> #include <sstream> #include <cstring> #include <string> #include <cmath> #include <vector> #include <queue> #include <stack> #include <map> #include <set> #include <list> #include <algorithm> #include <functional> #define sz(v) ((int)(v).size()) #define rep(i, n) for(int i = 0; i < n; i++) #define repf(i, a, b) for(int i = a; i <= b; i++) #define repd(i, a, b) for(int i = a; i >= b; i--) #define out(n) printf("%d\n", n) #define mset(a, b) memset(a, b, sizeof(a)) #define lint long long using namespace std; const int INF = 1 << 30; const int MaxN = 105; const double eps = 1e-9; const int chash = 12343; const double pie = acos(-1.0); int n, nodes; double x[MaxN], y[MaxN], r[MaxN]; double ans; int l_link[10 * MaxN], next[10 * MaxN]; double node[10 * MaxN][2]; int first[chash + 5]; int sgn(double d) { if(d > eps) return 1; if(d < -eps) return -1; return 0; } struct Inter { double x, y; Inter() {} bool operator < (const Inter &t) const { if(sgn(x - t.x) == 0) return (y < t.y); else return x < t.x; } }; Inter inter[MaxN]; double get_dist(double x1, double y1, double x2, double y2) { return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); } void init() { for(int i = 1; i <= n; i++) { scanf("%lf%lf", &x[i], &y[i]); r[i] = 1.0; } bool b[MaxN]; mset(b, true); for(int i = 1; i <= n; i++) { for(int j = i + 1; j <= n; j++) { if(sgn(x[i] - x[j]) == 0 && sgn(y[i] - y[j]) == 0 && sgn(r[i] - r[j]) == 0) { b[i] = false; break; } } } for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if(i != j && sgn(r[i] - r[j]) < 0) { if(sgn(get_dist(x[i], y[i], x[j], y[j]) - (r[j] - r[i])) <= 0) { b[i] = false; break; } } } } int j = 0; for(int i = 1; i <= n; i++) { if(b[i]) { j++; x[j] = x[i]; y[j] = y[i]; r[j] = r[i]; } } n = j; } double get_angle(double x, double y) { if(sgn(x) < 0) return atan(y / x) + pie; else if(sgn(x) > 0) { if(sgn(y) > 0) return atan(y / x); else return atan(y / x) + pie * 2.0; } else if(sgn(y) > 0) return pie / 2.0; else return pie * 3.0 / 2.0; } void get_cross(int i, int j, double &t1, double &t2) { double a, b, c, a1, b1, c1, x1, y1, x2, y2, t, l; a = (x[i] - x[j]) * 2.0; b = (y[i] - y[j]) * 2.0; c = r[j] * r[j] - r[i] * r[i] + x[i] * x[i] - x[j] * x[j] + y[i] * y[i] - y[j] * y[j]; a1 = b; b1 = -a; c1 = a1 * x[i] + b1 * y[i]; t = a * b1 - b * a1; x1 = (c * b1 - b * c1) / t; y1 = (a * c1 - c * a1) / t; l = sqrt(r[i] * r[i] - (x1 - x[i]) * (x1 - x[i]) - (y1 - y[i]) * (y1 - y[i])); t = sqrt(a1 * a1 + b1 * b1); x2 = x1 + l * a1 / t; y2 = y1 + l * b1 / t; x1 = x1 * 2.0 - x2; y1 = y1 * 2.0 - y2; t1 = get_angle(x1 - x[i], y1 - y[i]); t2 = get_angle(x2 - x[i], y2 - y[i]); if(sgn(t2 - t1) < 0) t1 = t1 - pie * 2.0; t = (t1 + t2) / 2.0; if((get_dist(x[j], y[j], x[i] + r[i] * cos(t), y[i] + r[i] * sin(t)) - r[j]) > 0) { t = t1; t1 = t2; t2 = t; if(sgn(t2) <= 0) t2 = t2 + pie * 2.0; else t1 = t1 - pie * 2.0; } } int get_index(double x, double y) { int i, t; t = (int)(fabs(x + y + eps) * 100000) % chash; i = first[t]; while(i != 0) { if(sgn(node[i][0] - x) == 0 && sgn(node[i][1] - y) == 0) { return i; } i = next[i]; } nodes++; node[nodes][0] = x; node[nodes][1] = y; next[nodes] = first[t]; first[t] = nodes; return nodes; } double get_chord(double r, double a) { return r * r / 2.0 * (a - sin(a)); } void get_node() { int i, j, k, top, t1, t2; nodes = 0; for(i = 1; i <= n; i++) { top = 0; for(j = 1; j <= n; j++) { if(i != j && sgn(get_dist(x[i], y[i], x[j], y[j]) - (r[i] + r[j])) < 0) { top++; get_cross(i, j, inter[top].x, inter[top].y); } } if(top > 0) { sort(inter + 1, inter + top + 1); k = 0; for(j = 1; j <= top; j++) { if(k == 0 || sgn(inter[j].x - inter[k].y) > 0) { k++; inter[k].x = inter[j].x; inter[k].y = inter[j].y; } else { if(sgn(inter[j].y - inter[k].y) > 0) { inter[k].y = inter[j].y; } } } top = k; while(top > 0 && sgn(inter[top].y - (inter[1].x + pie * 2.0)) >= 0) { if(sgn(inter[top].x - pie * 2.0 - inter[1].x) < 0) { inter[1].x = inter[top].x - pie * 2.0; } top--; } if(top > 0) { for(j = 1; j <= top - 1; j++) { ans += get_chord(r[i], inter[j + 1].x - inter[j].y); t1 = get_index(x[i] + r[i] * cos(inter[j + 1].x), y[i] + r[i] * sin(inter[j + 1].x)); t2 = get_index(x[i] + r[i] * cos(inter[j].y), y[i] + r[i] * sin(inter[j].y)); l_link[t1] = t2; } ans = ans + get_chord(r[i], inter[1].x + pie * 2.0 - inter[top].y); t1 = get_index(x[i] + r[i] * cos(inter[1].x), y[i] + r[i] * sin(inter[1].x)); t2 = get_index(x[i] + r[i] * cos(inter[top].y), y[i] + r[i] * sin(inter[top].y)); l_link[t1] = t2; } } else { ans += pie * r[i]; } } } void gao() { int i, j; bool vis[MaxN * 10]; ans = 0.0; get_node(); mset(vis, false); for(int i = 1; i <= nodes; i++) { if(!vis[i]) { j = i; do { vis[j] = true; ans += (node[l_link[j]][0] * node[j][1] - node[j][0] * node[l_link[j]][1]) / 2; j = l_link[j]; } while(j != i); } } } int main() { while(1 == scanf("%d", &n)) { init(); gao(); printf("%.2lf\n", ans); } return 0; }