题目描述
题解
这题思维难度不高,如果能想到扫描线应该很快就能想到正解,就是代码比较毒瘤。
首先在每个三角形的顶点和没两个三角形的交点建一条平行于y轴的扫描线,然后图形就被分成了若干的梯形(三角形),挨个求这些梯形的面积即可。
设一个梯形的上底是a,下底是b,高是h,则$S=frac{(a+b) imes h}{2}=中位线长度 imes h$,我们只需求出每个梯形的中位线长度即可。
对于两条相邻的扫描线x1,x2,它们之间的梯形的中位线就是$frac{x1+x2}{2}$截所有三角形所得的距离,因为数据小所以我们可以不用线段树维护。
具体实现细节建议用向量而非解析式。
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 using namespace std; 6 const long double eps = 1e-8; 7 const long double inf = 2000000; 8 struct Point{ 9 long double x, y; 10 Point operator + (Point v) { 11 Point ret = Point{x + v.x, y + v.y}; 12 return ret; 13 } 14 Point operator - (Point v) { 15 Point ret = Point{x - v.x, y - v.y}; 16 return ret; 17 } 18 Point operator * (long double v) { 19 Point ret = Point{x * v, y * v}; 20 return ret; 21 } 22 }t[110][4]; 23 long double p[100000]; 24 int tot; 25 int n; 26 inline int sgn(long double x) { 27 if (fabs(x) < eps) return 0; 28 return x > 0 ? 1 : -1; 29 } 30 inline long double dot(Point a, Point b) { 31 return a.x * b.x + a.y * b.y; 32 } 33 inline long double cross(Point a, Point b) { 34 return a.x * b.y - a.y * b.x; 35 } 36 inline bool is_intersect(Point a, Point b, Point c, Point d) {//判断是否相交 37 long double f1 = cross(b - a, c - a); 38 long double f2 = cross(b - a, d - a); 39 long double f3 = cross(d - c, a - c); 40 long double f4 = cross(d - c, b - c); 41 return (f1 * f2 < 0 && f3 * f4 < 0); 42 } 43 inline Point get_intersect(Point a, Point b, Point c, Point d) { 44 long double s1 = cross(c - a, d - c), s2 = cross(b - a, d - c); 45 return a + (b - a) * (s1 / s2); 46 } 47 bool cmp(Point x, Point y) { 48 return x.x < y.x; 49 } 50 long double ans; 51 Point seg[10010]; 52 inline long double solve(long double x) { 53 Point P = Point{x, -inf}, Q = Point{x, inf}; 54 int m = 0; 55 for (int i = 1; i <= n; i++) { 56 int top = 0; 57 long double y[3]; 58 for (int j = 1; j <= 3; j++) { 59 int nxt_j = j + 1; 60 if (nxt_j == 4) nxt_j = 1; 61 if (is_intersect(t[i][j], t[i][nxt_j], P, Q)) { 62 y[++top] = get_intersect(t[i][j], t[i][nxt_j], P, Q).y; 63 } 64 } 65 if (top == 2) seg[++m] = Point{min(y[1], y[2]), max(y[1], y[2])}; 66 } 67 sort(seg + 1, seg + m + 1, cmp); 68 long double l = -inf, r = -inf, ret = 0; 69 for (int i = 1; i <= m; i++) { 70 if (sgn(seg[i].x - r) > 0) ret += r - l, l = seg[i].x; 71 r = max(r, seg[i].y); 72 } 73 ret += r - l; 74 return ret; 75 } 76 int main() { 77 cin >> n; 78 for (int i = 1; i <= n; ++i) { 79 for (int j = 1; j <= 3; ++j) { 80 cin >> t[i][j].x >> t[i][j].y; 81 p[++tot] = t[i][j].x; 82 } 83 } 84 for (int i = 1; i <= n; ++i) { 85 for (int j = i + 1; j <= n; ++j) { 86 //枚举两个三角形求它们边的交点 87 for (int k = 1; k <= 3; ++k) { 88 for (int l = 1; l <= 3; l++) { 89 int nxt_k = k + 1; 90 if (nxt_k == 4) nxt_k = 1; 91 int nxt_l = l + 1; 92 if (nxt_l == 4) nxt_l = 1; 93 if (is_intersect(t[i][k], t[i][nxt_k], t[j][l], t[j][nxt_l])) { 94 p[++tot] = get_intersect(t[i][k], t[i][nxt_k], t[j][l], t[j][nxt_l]).x; 95 } 96 } 97 } 98 } 99 } 100 sort(p + 1, p + 1 + tot); 101 for (int i = 2; i <= tot; i++) { 102 if (sgn(p[i] - p[i - 1]) != 0) { 103 ans += (p[i] - p[i - 1]) * solve((p[i] + p[i - 1]) / 2);//算梯形面积 104 } 105 } 106 printf("%.2Lf", ans-eps);//卡精度 107 return 0; 108 }