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


    题目描述

    题解

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

    首先在每个三角形的顶点和没两个三角形的交点建一条平行于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 }
  • 相关阅读:
    java的hashcode和equals
    Spring 注入所得
    Action注入错误
    oracle中的替换函数replace和translate函数
    CSS div水平垂直居中和div置于底部
    java double类型保留两位小数4种方法
    Delphi写的DLL回调C#
    Java基础进阶整理
    j技术方案
    SetForegroundWindow激活窗口
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/12716919.html
Copyright © 2020-2023  润新知