zoukankan      html  css  js  c++  java
  • 2018 CCPC- Guilin Site-L. Two Ants (几何)

    2018 CCPC- Guilin Site-L. Two Ants (几何)

    题面:

    题意:

    给定两个线段,颜色分别为白色和黑色,现在问你在二维平面坐标系中只能看到白色线段的区域面积是多少?

    思路:

    主要是分类讨论,情况较多,一定要按照优先顺序详细讨论即可。

    下面我将给出情形,并且顺序是优先级由高到低。

    • 白色线段退化成点,答案为0

    • 黑色线段退化成点,答案为inf

    • 两线段规范相交,答案为0

    • 两线段非规范相交:

      • 若有共线答案为0。
      • 否则即交点在端点,答案为inf
    • 两线段不相交:

      • 黑色线段的两点在白色线段的两侧,答案为0.

      • 否则:

        • 两个线段端点彼此之间的连线,若有交点,判断其相对位置,如果相对于白色线段不与黑色线段同侧,则计算该点与白色线段构成的面积即是答案。

        • 若没有交点(平行),或者交点都在黑色线段同侧,则答案为inf.

          如下图:

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    // `计算几何模板`
    const double eps = 1e-14;
    const double inf = 1e20;
    const double pi = acos(-1.0);
    const int maxp = 1010;
    //`Compares a double to zero`
    int sgn(double x)
    {
        if (fabs(x) < eps) { return 0; }
        else { return x < 0 ? -1 : 1; }
    }
    //square of a double
    inline double sqr(double x) {return x * x;}
    struct Point {
        double x, y;
        Point() {}
        Point(double _x, double _y)
        {
            x = _x;
            y = _y;
        }
        void input()
        {
            scanf("%lf%lf", &x, &y);
        }
        void output()
        {
            printf("%.2f %.2f
    ", x, y);
        }
        bool operator == (Point b)const
        {
            return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
        }
        bool operator < (Point b)const
        {
            return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
        }
        Point operator -(const Point &b)const
        {
            return Point(x - b.x, y - b.y);
        }
        //叉积
        double operator ^(const Point &b)const
        {
            return x * b.y - y * b.x;
        }
        //点积
        double operator *(const Point &b)const
        {
            return x * b.x + y * b.y;
        }
        //返回长度
        double len()
        {
            return hypot(x, y); //库函数
        }
        //返回长度的平方
        double len2()
        {
            return x * x + y * y;
        }
        //返回两点的距离
        double distance(Point p)
        {
            return hypot(x - p.x, y - p.y);
        }
        Point operator +(const Point &b)const
        {
            return Point(x + b.x, y + b.y);
        }
        Point operator *(const double &k)const
        {
            return Point(x * k, y * k);
        }
        Point operator /(const double &k)const
        {
            return Point(x / k, y / k);
        }
        //`计算pa  和  pb 的夹角`
        //`就是求这个点看a,b 所成的夹角`
        //`测试 LightOJ1203`
        double rad(Point a, Point b)
        {
            Point p = *this;
            return fabs(atan2( fabs((a - p) ^ (b - p)), (a - p) * (b - p) ));
        }
        //`化为长度为r的向量`
        Point trunc(double r)
        {
            double l = len();
            if (!sgn(l)) { return *this; }
            r /= l;
            return Point(x * r, y * r);
        }
        //`逆时针旋转90度`
        Point rotleft()
        {
            return Point(-y, x);
        }
        //`顺时针旋转90度`
        Point rotright()
        {
            return Point(y, -x);
        }
        //`绕着p点逆时针旋转angle`
        Point rotate(Point p, double angle)
        {
            Point v = (*this) - p;
            double c = cos(angle), s = sin(angle);
            return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
        }
    };
    struct Line {
        Point s, e;
        Line() {}
        Line(Point _s, Point _e)
        {
            s = _s;
            e = _e;
        }
        bool operator ==(Line v)
        {
            return (s == v.s) && (e == v.e);
        }
        //`根据一个点和倾斜角angle确定直线,0<=angle<pi`
        Line(Point p, double angle)
        {
            s = p;
            if (sgn(angle - pi / 2) == 0) {
                e = (s + Point(0, 1));
            } else {
                e = (s + Point(1, tan(angle)));
            }
        }
        //ax+by+c=0
        Line(double a, double b, double c)
        {
            if (sgn(a) == 0) {
                s = Point(0, -c / b);
                e = Point(1, -c / b);
            } else if (sgn(b) == 0) {
                s = Point(-c / a, 0);
                e = Point(-c / a, 1);
            } else {
                s = Point(0, -c / b);
                e = Point(1, (-c - a) / b);
            }
        }
        void input()
        {
            s.input();
            e.input();
        }
        void adjust()
        {
            if (e < s) { swap(s, e); }
        }
        //求线段长度
        double length()
        {
            return s.distance(e);
        }
        //`返回直线倾斜角 0<=angle<pi`
        double angle()
        {
            double k = atan2(e.y - s.y, e.x - s.x);
            if (sgn(k) < 0) { k += pi; }
            if (sgn(k - pi) == 0) { k -= pi; }
            return k;
        }
        //`点和直线关系`
        //`1  在左侧`
        //`2  在右侧`
        //`3  在直线上`
        int relation(Point p)
        {
            int c = sgn((p - s) ^ (e - s));
            if (c < 0) { return 1; }
            else if (c > 0) { return 2; }
            else { return 3; }
        }
        // 点在线段上的判断
        bool pointonseg(Point p)
        {
            return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s) * (p - e)) <= 0;
        }
        //`两向量平行(对应直线平行或重合)`
        bool parallel(Line v)
        {
            return sgn((e - s) ^ (v.e-v.s)) == 0;
        }
        //`两线段相交判断`
        //`2 规范相交`
        //`1 非规范相交`
        //`0 不相交`
        int segcrossseg(Line v)
        {
            int d1 = sgn((e - s) ^ (v.s - s));
            int d2 = sgn((e - s) ^ (v.e-s));
            int d3 = sgn((v.e-v.s) ^ (s - v.s));
            int d4 = sgn((v.e-v.s) ^ (e - v.s));
            if ( (d1 ^ d2) == -2 && (d3 ^ d4) == -2 ) { return 2; }
            return (d1 == 0 && sgn((v.s - s) * (v.s - e)) <= 0) ||
                   (d2 == 0 && sgn((v.e-s) * (v.e-e)) <= 0) ||
                   (d3 == 0 && sgn((s - v.s) * (s - v.e)) <= 0) ||
                   (d4 == 0 && sgn((e - v.s) * (e - v.e)) <= 0);
        }
        //`直线和线段相交判断`
        //`-*this line   -v seg`
        //`2 规范相交`
        //`1 非规范相交`
        //`0 不相交`
        int linecrossseg(Line v)
        {
            int d1 = sgn((e - s) ^ (v.s - s));
            int d2 = sgn((e - s) ^ (v.e-s));
            if ((d1 ^ d2) == -2) { return 2; }
            return (d1 == 0 || d2 == 0);
        }
        //`两直线关系`
        //`0 平行`
        //`1 重合`
        //`2 相交`
        int linecrossline(Line v)
        {
            if ((*this).parallel(v)) {
                return v.relation(s) == 3;
            }
            return 2;
        }
        //`求两直线的交点`
        //`要保证两直线不平行或重合`
        Point crosspoint(Line v)
        {
            double a1 = (v.e-v.s) ^ (s - v.s);
            double a2 = (v.e-v.s) ^ (e - v.s);
            return Point((s.x * a2 - e.x * a1) / (a2 - a1), (s.y * a2 - e.y * a1) / (a2 - a1));
        }
        //点到直线的距离
        double dispointtoline(Point p)
        {
            return fabs((p - s) ^ (e - s)) / length();
        }
        //点到线段的距离
        double dispointtoseg(Point p)
        {
            if (sgn((p - s) * (e - s)) < 0 || sgn((p - e) * (s - e)) < 0) {
                return min(p.distance(s), p.distance(e));
            }
            return dispointtoline(p);
        }
        //`返回线段到线段的距离`
        //`前提是两线段不相交,相交距离就是0了`
        double dissegtoseg(Line v)
        {
            return min(min(dispointtoseg(v.s), dispointtoseg(v.e)), min(v.dispointtoseg(s), v.dispointtoseg(e)));
        }
        //`返回点p在直线上的投影`
        Point lineprog(Point p)
        {
            Point v = e - s;
            return s + ( (v * (v * (p - s))) / (v.len2()) );
        }
        //`返回点p关于直线的对称点`
        Point symmetrypoint(Point p)
        {
            Point q = lineprog(p);
            return Point(2 * q.x - p.x, 2 * q.y - p.y);
        }
    };
    
    int main()
    {
        int T;
        cin >> T;
        Line w, b;
        int cas = 0;
        Line l1, l2, l3, l4;
        Point cp;
        int sg;
        double ans;
        while (T--) {
            ++cas;
            w.input();
            b.input();
            if (w.s == w.e) {
                printf("Case %d: 0.000
    ", cas);
            } else if (b.s == b.e) {
                printf("Case %d: inf
    ", cas);
            } else {
                int crs = w.segcrossseg(b);
                if (crs == 2) {
                    printf("Case %d: 0.000
    ", cas);
                } else if (crs == 1) {
                    if (w.relation(b.s) == 3 && w.relation(b.e) == 3) {
                        printf("Case %d: 0.000
    ", cas);
                    } else if (w.pointonseg(b.s) || w.pointonseg(b.e)) {
                        printf("Case %d: inf
    ", cas);
                    } else {
                        printf("Case %d: 0.000
    ", cas);
                    }
                } else {
                    if (sgn((w.e - w.s) ^ (b.e - w.s)) * sgn((w.e - w.s) ^ (b.s - w.s)) <= 0) {
                        printf("Case %d: 0.000
    ", cas);
                    } else {
                        sg = sgn((w.e - w.s) ^ (b.e - w.s));
                        bool flag = false;
                        l1 = Line(w.e, b.e);
                        l2 = Line(w.s, b.s);
                        l3 = Line(w.e, b.s);
                        l4 = Line(w.s, b.e);
                        if (!l1.parallel(l2)) {
                            cp = l1.crosspoint(l2);
                            if (sgn((w.e - w.s) ^ (cp - w.s)) != sg) {
                                flag = true;
                                ans = abs((w.e - w.s) ^ (cp - w.s)) / 2;
                            }
                        }
                        if (!l3.parallel(l4)) {
                            cp = l3.crosspoint(l4);
                            if (sgn((w.e - w.s) ^ (cp - w.s)) != sg) {
                                flag = true;
                                ans = abs((w.e - w.s) ^ (cp - w.s)) / 2;
                            }
                        }
                        if (!flag) {
                            printf("Case %d: inf
    ", cas);
                        } else {
                            printf("Case %d: %.10f
    ", cas, ans);
                        }
                    }
                }
            }
        }
    }
    
  • 相关阅读:
    无限维
    黎曼流形
    why we need virtual key word
    TOJ 4119 Split Equally
    TOJ 4003 Next Permutation
    TOJ 4002 Palindrome Generator
    TOJ 2749 Absent Substrings
    TOJ 2641 Gene
    TOJ 2861 Octal Fractions
    TOJ 4394 Rebuild Road
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/13996423.html
Copyright © 2011-2022 走看看