以前写过PSLG模拟的版本,今天写了一下扫描线做这题。
其实这题可以用set存线段来做,类似于判断直线交的做法。不过实现起来有点麻烦,于是我就直接暴力求交点了。
代码如下:

1 #include <set> 2 #include <queue> 3 #include <cmath> 4 #include <cstdio> 5 #include <cstring> 6 #include <iomanip> 7 #include <iostream> 8 #include <algorithm> 9 10 using namespace std; 11 12 const double EPS = 1e-10; 13 inline int sgn(double x) { return (x > EPS) - (x < -EPS);} 14 typedef pair<double, double> Point; 15 #define x first 16 #define y second 17 Point operator + (Point a, Point b) { return Point(a.x + b.x, a.y + b.y);} 18 Point operator - (Point a, Point b) { return Point(a.x - b.x, a.y - b.y);} 19 Point operator * (Point a, double p) { return Point(a.x * p, a.y * p);} 20 Point operator / (Point a, double p) { return Point(a.x / p, a.y / p);} 21 22 inline double cross(Point a, Point b) { return a.x * b.y - a.y * b.x;} 23 inline double dot(Point a, Point b) { return a.x * b.x + a.y * b.y;} 24 inline double veclen(Point a) { return sqrt(dot(a, a));} 25 inline Point rotate(Point a) { 26 double cosx = cos(0.001), sinx = sin(0.001); 27 return Point(a.x * cosx - a.y * sinx, a.x * sinx + a.y * cosx); 28 } 29 30 struct Line { 31 Point s, t; 32 Line() {} 33 Line(Point s, Point t) : s(s), t(t) {} 34 Point vec() { return t - s;} 35 Point point(double p) { return s + vec() * p;} 36 } ; 37 inline Point llint(Line a, Line b) { return a.point(cross(b.vec(), a.s - b.s) / cross(a.vec(), b.vec()));} 38 void scan(Point &a) { cin >> a.x >> a.y;} 39 const int N = 55; 40 Point tri[N][4]; 41 42 bool check(int n) { 43 for (int i = 0; i < n; i++) { 44 for (int j = 0; j < 3; j++) { 45 if (sgn(tri[i][j].x - tri[i][j + 1].x) == 0) return 1; 46 } 47 } 48 return 0; 49 } 50 void adjust(int n) { for (int i = 0; i < n; i++) for (int j = 0; j < 4; j++) tri[i][j] = rotate(tri[i][j]);} 51 inline bool between(Point p, Point a, Point b) { return sgn(dot(a - p, b - p)) <= 0;} 52 bool cmpy(Point a, Point b) { return a.y < b.y;} 53 54 bool triline(Line l, int id, Point *ip) { 55 Point tmp[3]; 56 int tt = 0; 57 for (int i = 0; i < 3; i++) { 58 tmp[tt] = llint(l, Line(tri[id][i], tri[id][i + 1])); 59 if (between(tmp[tt], tri[id][i], tri[id][i + 1])) tt++; 60 } 61 sort(tmp, tmp + tt, cmpy); 62 ip[0] = tmp[0], ip[1] = tmp[tt - 1]; 63 return tt > 1; 64 } 65 66 typedef pair<double, int> Break; 67 bool cmp(Break a, Break b) { return sgn(a.x - b.x) < 0 || sgn(a.x - b.x) == 0 && a.y < b.y;} 68 Break ips_l[N << 2], ips_r[N << 2]; 69 double area[N], len_l[N], len_r[N], event[N * N << 4]; 70 void scanline(int n) { 71 memset(area, 0, sizeof(area)); 72 int tt = 0; 73 for (int i = 0; i < n; i++) { 74 for (int j = 0; j < 3; j++) { 75 Point a = tri[i][j], b = tri[i][j + 1]; 76 event[tt++] = a.x; 77 for (int k = 0; k < n; k++) { 78 for (int l = 0; l < 3; l++) { 79 Point c = tri[k][l], d = tri[k][l + 1]; 80 if (sgn(cross(b - a, d - c)) == 0) continue; 81 Point ip = llint(Line(a, b), Line(c, d)); 82 //cout << ip.x << ' ' << ip.y << endl; 83 if (between(ip, a, b) && between(ip, c, d)) { 84 event[tt++] = ip.x; 85 } 86 } 87 } 88 } 89 } 90 sort(event, event + tt); 91 tt = (int) (unique(event, event + tt) - event); 92 Line cur; 93 Point tmp[2]; 94 for (int i = 1, c, cnt; i < tt; i++) { 95 if (sgn(event[i - 1] - event[i]) == 0) continue; 96 c = 0; 97 cur = Line(Point(event[i - 1] + EPS, 0.0), Point(event[i - 1] + EPS, 1.0)); 98 for (int j = 0; j < n; j++) { 99 if (triline(cur, j, tmp)) { 100 ips_l[c++] = Break(tmp[0].y, 1), ips_l[c++] = Break(tmp[1].y, -1); 101 } 102 } 103 sort(ips_l, ips_l + c, cmp); 104 cnt = 0; 105 memset(len_l, 0, sizeof(len_l)); 106 for (int j = 0; j < c; j++) { 107 if (cnt > 0) len_l[cnt] += ips_l[j].x - ips_l[j - 1].x; 108 cnt += ips_l[j].y; 109 } 110 c = 0; 111 cur = Line(Point(event[i] - EPS, 0.0), Point(event[i] - EPS, 1.0)); 112 for (int j = 0; j < n; j++) { 113 if (triline(cur, j, tmp)) { 114 ips_r[c++] = Break(tmp[0].y, 1), ips_r[c++] = Break(tmp[1].y, -1); 115 } 116 } 117 sort(ips_r, ips_r + c, cmp); 118 cnt = 0; 119 memset(len_r, 0, sizeof(len_r)); 120 for (int j = 0; j < c; j++) { 121 if (cnt > 0) len_r[cnt] += ips_r[j].x - ips_r[j - 1].x; 122 cnt += ips_r[j].y; 123 } 124 for (int j = 1; j <= n; j++) area[j] += (len_l[j] + len_r[j]) * (event[i] - event[i - 1]) / 2; 125 } 126 } 127 128 int main() { 129 ios::sync_with_stdio(0); 130 cout << setiosflags(ios::fixed) << setprecision(8); 131 int T, n; 132 cin >> T; 133 while (T-- && cin >> n) { 134 int tt = 0; 135 for (int i = 0; i < n; i++) { 136 for (int j = 0; j < 3; j++) scan(tri[tt][j]); 137 tri[tt][3] = tri[tt][0]; 138 if (sgn(cross(tri[tt][1] - tri[tt][0], tri[tt][2] - tri[tt][0]))) tt++; 139 } 140 while (check(tt)) adjust(tt); 141 scanline(tt); 142 for (int i = 1; i <= n; i++) area[i] = fabs(area[i]); 143 for (int i = 1; i <= n; i++) cout << area[i] << endl; 144 } 145 return 0; 146 }
——written by Lyon