[CQOI2005]三角形面积并(计算几何+扫描线)

题目描述

题解

这题思维难度不高,如果能想到扫描线应该很快就能想到正解,就是代码比较毒瘤。

首先在每个三角形的顶点和没两个三角形的交点建一条平行于y轴的扫描线,然后图形就被分成了若干的梯形(三角形),挨个求这些梯形的面积即可。

设一个梯形的上底是a,下底是b,高是h,则$S=\frac{(a+b) \times h}{2}=中位线长度 \times 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 }

猜你喜欢

转载自www.cnblogs.com/zcr-blog/p/12716919.html