zoukankan      html  css  js  c++  java
  • 暑假集训 || 计算几何

    看起来很挫的……

    线段与直线

    const int SZ = 150;
    const int INF = 1e9+10;
    const double eps = 1e-8;
    const double pi = acos(-1.0);
    int sgn(double x)
    {
        if(fabs(x) < eps) return 0;
        if(x < 0) return -1;
        return 1;
    }
    struct Point
    {
        double x, y;
        Point () {}
        Point (double x, double y) : x(x), y(y) {}
        Point operator +(const Point &a)const{
            return Point(x + a.x, y + a.y);
        }
        Point operator -(const Point &a)const{
            return Point(x - a.x, y - a.y);
        }
        bool operator ==(const Point &a)const{
            if(sgn(x - a.x) == 0 && sgn(y - a.y) == 0) return true;
            return false;
        }
        bool operator !=(const Point &a)const{
            return x != a.x || y != a.y;
        }
        bool operator <(const Point &a)const{
            if(a.x != x) return x < a.x;//以x作为第一关键字排序
            return y < a.y;
        }
        double operator *(const Point &a)const{//点乘
            return x * a.x + y * a.y;
        }
        double operator ^(const Point &a)const{//叉乘
            return x * a.y - y * a.x;
        }
    }p[SZ];
    struct edge
    {
        Point s, e;
    }line[SZ];
    double xmul(Point a, Point b, Point c) //ab * ac, xmul<0表示p0在se左
    {
        return (b - a) ^ (c - a);
    }
    double getdis(Point a, Point b)//点a与点b之间的距离
    {
        return sqrt((a-b) * (a-b));
    }
    bool online(Point p, edge l)//p是否在线段l上
    {
        return sgn((p-l.s) ^ (l.e-l.s)) == 0 && sgn((p-l.s) * (p-l.e)) <= 0;
    }
    bool checkcross(edge l1, edge l2)//判断直线l1是否与线段l2相交
    {
        if(sgn(xmul(l2.s, l1.s, l1.e)) * sgn(xmul(l2.e, l1.s, l1.e)) <= 0) return true;
        return false;
    }
    bool onseg(edge l1, edge l2)//判断线段l1是否与线段l2共线但不重合
    {
        int flag = 0;
        if(max(l1.s.x, l1.e.x) < min(l2.s.x, l2.e.x) || max(l2.s.x, l2.e.x) < min(l1.s.x, l1.e.x)) flag++;
        if(max(l1.s.y, l1.e.y) < min(l2.s.y, l2.e.y) || max(l2.s.y, l2.e.y) < min(l1.s.y, l1.e.y)) flag++;
        if(getk(l1.s, l1.e) - getk(l2.s, l2.e) == 0) flag++;
        if(flag == 3) return true;
        return false;
    }
    bool checksegcross(edge l1, edge l2)//判断线段l1是否与线段l2相交
    {
        int flag = 0;
        if(((l2.e-l2.s) ^ (l1.s-l2.s)) * ((l2.e-l2.s) ^ (l1.e-l2.s)) <= 0) flag++;
        if(((l1.e-l1.s) ^ (l2.s-l1.s)) * ((l1.e-l1.s) ^ (l2.e-l1.s)) <= 0) flag++;
        if(!onseg(a, b)) flag++;
        if(flag == 3) return true;
        return false;
    }
    View Code

    求凸包:

    bool cmp(Point a, Point b)
    {
        double tmp = xmul(p[0], a, b);
        if(sgn(tmp) < 0) return false;
        if(sgn(tmp) > 0) return true;
        return getdis(p[0], a) < getdis(p[0], b);
    }
    int n;
    double graham()
    {
        int k = 0;
        for(int i = 1; i < n; i++)
            if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i;
        swap(p[0], p[k]);
        sort(p+1, p+n, cmp);
        int top = 0;
        s[top++] = p[0]; s[top++] = p[1];
        for(int i = 2;i < n;i ++)
        {
            while(top > 1 && ((s[top-1] - s[top-2]) ^ (p[i] - s[top-2])) < 0)
                top --;
            s[top++] = p[i];
        }
        double ans = 0;
        for(int i = 0; i < top; i++)
            ans += getdis(s[i], i == top-1 ? s[0] : s[i+1]);
        return ans;
    }
    View Code

    POJ 1113

    用墙围起来,墙距离原图形至少L距离

    就是凸包的周长加上一个半径为L的圆

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    using namespace std;
    const int SZ = 1100;
    const int INF = 1e9+10;
    const double eps = 1e-8;
    const double pi = acos(-1.0);
    int sgn(double x)
    {
        if(fabs(x) < eps) return 0;
        if(x < 0) return -1;
        return 1;
    }
    struct Point
    {
        double x, y;
        Point operator +(const Point &a)const{
            return (Point){a.x + x, a.y + y};
        }
        Point operator -(const Point &a)const{
            return (Point){a.x - x, a.y - y};
        }
        bool operator ==(const Point &a)const{
            if(sgn(a.x - x) == 0 && sgn(a.y - y) == 0) return true;
            return false;
        }
        bool operator !=(const Point &a)const{
            return a.x != x || a.y != y;
        }
        bool operator <(const Point &a)const{
            if(a.x != x) return a.x < x;
            return a.y < y;
        }
        double operator *(const Point &a)const{
            return a.x * x + a.y * y;
        }
        double operator ^(const Point &a)const{
            return a.x * y - a.y * x;
            //return x * a.y - y * a.x;
        }
    }p[SZ], s[SZ];
    double xmul(Point p0, Point p1, Point p2) //p0p1 * p0p2 xmul<0 p0在p1p2左
    {
        return (p1 - p0) ^ (p2 - p0);
    }
    double getdis(Point a, Point b)
    {
        return sqrt((a-b) * (a-b));
    }
    bool cmp(Point a, Point b)
    {
        double tmp = xmul(p[0], a, b);
        if(sgn(tmp) < 0) return false;
        if(sgn(tmp) > 0) return true;
        return getdis(p[0], a) < getdis(p[0], b);
    }
    int n;
    double graham()
    {
        int k = 0;
        for(int i = 1; i < n; i++)
            if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i;
        swap(p[0], p[k]);
        sort(p+1, p+n, cmp);
        int top = 0;
        s[top++] = p[0]; s[top++] = p[1];
        for(int i = 2;i < n;i ++)
        {
            while(top > 1 && ((s[top-1] - s[top-2]) ^ (p[i] - s[top-2])) < 0)
                top --;
            s[top++] = p[i];
        }
        double ans = 0;
        for(int i = 0; i < top; i++)
            ans += getdis(s[i], i == top-1 ? s[0] : s[i+1]);
        return ans;
    }
    int main()
    {
        int L;
        scanf("%d %d", &n, &L);
        for(int i = 0; i < n; i++)
        {
            int a, b;
            scanf("%d %d", &a, &b);
            p[i] = (Point){a, b};
        }
        double ans = graham();
        ans += pi * 2 * L;
        printf("%.0f
    ", ans);
        return 0;
    }
    View Code

    POJ 1696

    题意:只能直走或者左转,最多能到达多少个点

    思路:合理选择出发点肯定每个点都能到达,贪心的思想

    每次选以上一个位置为极点,极角最小的点。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 #include <queue>
     7 using namespace std;
     8 const int SZ = 150;
     9 const int INF = 1e9+10;
    10 const double eps = 1e-8;
    11 const double pi = acos(-1.0);
    12 int sgn(double x)
    13 {
    14     if(fabs(x) < eps) return 0;
    15     if(x < 0) return -1;
    16     return 1;
    17 }
    18 struct Point
    19 {
    20     int id;
    21     double x, y;
    22     Point operator -(const Point &a)const{
    23         return (Point){id, x - a.x, y - a.y};
    24     }
    25     double operator *(const Point &a)const{
    26         return a.x * x + a.y * y;
    27     }
    28     double operator ^(const Point &b)const
    29     {
    30         return x*b.y - y*b.x;
    31     }
    32 }p[SZ];
    33 double xmul(Point p0, Point p1, Point p2) //p0p1 * p0p2 xmul<0 p0在p1p2左
    34 {
    35     return (p1 - p0) ^ (p2 - p0);
    36 }
    37 double getdis(Point a, Point b)
    38 {
    39     return sqrt((a-b) * (a-b));
    40 }
    41 int idx;//标记上一个位置 为极点
    42 bool cmp(Point a, Point b)
    43 {
    44     double tmp = xmul(p[idx], a, b);
    45     if(sgn(tmp) < 0) return false;
    46     if(sgn(tmp) > 0) return true;
    47     return getdis(p[idx], a) < getdis(p[idx], b);
    48 }
    49 int main()
    50 {
    51     int T;
    52     scanf("%d", &T);
    53     while(T--)
    54     {
    55         int n, id;
    56         scanf("%d", &n);
    57         for(int i = 1; i <= n; i++)
    58             scanf("%d %lf %lf", &p[i].id, &p[i].x, &p[i].y);
    59         int k = 1;
    60         for(int i = 2; i <= n; i++)
    61             if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i;
    62         swap(p[1], p[k]);
    63         idx = 1;
    64         for(int i = 2; i <= n; i++)
    65         {
    66             sort(p+i, p+1+n, cmp);
    67             idx++;
    68         }
    69         printf("%d", n);
    70         for(int i = 1; i <= n; i++)
    71             printf(" %d", p[i].id);
    72         printf("
    ");
    73     }
    74     return 0;
    75 }
    View Code

    HDU 6325

    题意:每个点有一个标号,要求x坐标递增,代价为两个坐标的叉积。 求起点到终点总代价最小的飞行路线,并输出字典序最小的路线

    思路:因为凸包是求逆时针的时候面积包住所有点的面积最大,那么我们题目这样是顺时针,相反的就是面积最小,所以这题就是求顺时针的凸包,那肯定就包括起点、终点、凸包的拐点了,只要把上凸包求出来就好

    就是改一下cmp和求凸包的时候的更新函数

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    using namespace std;
    const int SZ = 200200;
    const int INF = 1e9+10;
    const double eps = 1e-8;
    const double pi = acos(-1.0);
    #define getT int T;scanf("%d", &T); while(T--)
    int sgn(double x)
    {
        if(fabs(x) < eps) return 0;
        if(x < 0) return -1;
        return 1;
    }
    struct Point
    {
        double x, y;
        int id;
        Point () {}
        Point (double x, double y) : x(x), y(y) {}
        Point operator -(const Point &a)const{
            return (Point){x - a.x, y - a.y};
        }
        double operator *(const Point &a)const{//点乘
            return x * a.x + y * a.y;
        }
        double operator ^(const Point &a)const{//叉乘
            return x * a.y - y * a.x;
        }
    }p[SZ];
    double xmul(Point a, Point b, Point c) //ab * ac, xmul<0表示p0在se左
    {
        return (b - a) ^ (c - a);
    }
    int n;
    bool cmp(Point a, Point b)
    {
        if(a.x != b.x) return a.x < b.x;
        return a.id > b.id;
    }
    int top;
    int s[SZ];
    void graham()
    {
        top = 0;
        sort(p+1, p+n+1, cmp);
        s[++top] = 1; s[++top] = 2;
        for(int i = 3; i <= n; i++)
        {
            while(top > 1)
            {
                int x = s[top]; top--;
                int y = s[top];
                if(xmul(p[y], p[i], p[x]) > 0 || (xmul(p[y], p[i], p[x]) == 0 && p[i].id > p[x].id))
                {
                    s[++top] = x;
                    break;
                }
            }
            s[++top] = i;
        }
    }
    int main()
    {
        getT
        {
            scanf("%d", &n);
            for(int i = 1; i <= n; i++)
            {
                double x, y;
                scanf("%lf %lf", &x, &y);
                p[i] = Point(x, y);
                p[i].id = i;
            }
            graham();
            printf("%d", p[s[1]].id);
            for(int i = 2; i <= top; i++)
                printf(" %d", p[s[i]].id);
            printf("
    ");
        }
        return 0;
    }
    View Code

    BZOJ 1007

    给出n条形如y = kx + b的直线,求从y轴正无穷向下看能看到哪些直线

    ·三维凸包

    HDU 3662 模板。。很强

    #include <iostream>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    using namespace std;
    const int SZ = 320;
    const int INF = 1e9+10;
    const double eps = 1e-8;
    const double pi = acos(-1.0);
    int sgn(double x)
    {
        if(fabs(x) < eps) return 0;
        if(x < 0) return -1;
        return 1;
    }
    struct Point
    {
        double x, y, z;
        Point () {}
        Point (double x, double y, double z) : x(x), y(y), z(z) {}
        Point operator -(const Point &a)const{
            return Point(x - a.x, y - a.y, z - a.z);
        }
        double operator *(const Point &a)const{//点乘
            return x * a.x + y * a.y + z * a.z;
        }
        Point operator ^(const Point &a)const{//叉乘
            return Point(y * a.z - z * a.y, z * a.x - x * a.z, x * a.y - y * a.x);
        }
    }p[SZ];
    Point xmul(Point a, Point b, Point c) //ab * ac, xmul<0表示p0在se左
    {
        return (b - a) ^ (c - a);
    }
    double getdis(Point a, Point b)//点a与点b之间的距离
    {
        return sqrt((a-b) * (a-b));
    }
    double getlen(Point a)
    {
        return a.x*a.x + a.y*a.y + a.z*a.z;
    }
    struct Face
    {
        int a, b, c;
        bool flag;
    } face;
    struct CH3D
    {
        struct face
        {
            int a,b,c;//表示凸包一个面上三个点的编号
            bool flag;//表示该面是否属于最终凸包中的面
        };
    
        int n; //初始顶点数
        Point P[SZ]; //初始顶点
    
        int num; //凸包表面的三角形数
        face F[8*SZ];//凸包表面的三角形
    
        int g[SZ][SZ];
    
        Point cross(const Point &a, const Point &b, const Point &c)
        {
            return (b-a) ^ (c-a);
        }
        double area(Point a,Point b,Point c) //三角形面积*2
        {
            return getlen((b-a) ^ (c-a));
        }
    
        double volume(Point a,Point b,Point c,Point d) //四面体有向体积*6
        {
            return ((b-a) ^ (c-a)) * (d-a);
        }
    
        double dblcmp(Point &p,face &f) //正:点在面同向
        {
            Point p1 = P[f.b]-P[f.a];
            Point p2 = P[f.c]-P[f.a];
            Point p3 = p-P[f.a];
            return (p1 ^ p2) * p3;
        }
    
        void deal(int p,int a,int b)
        {
            int f = g[a][b];
            face add;
            if(F[f].flag)
            {
                if(dblcmp(P[p], F[f]) > eps)
                    dfs(p, f);
                else
                {
                    add.a = b;
                    add.b = a;
                    add.c = p;
                    add.flag = 1;
                    g[p][b] = g[a][p] = g[b][a] = num;
                    F[num++] = add;
                }
            }
        }
    
        void dfs(int p,int now) //递归搜索所有应该从凸包内删除的面
        {
            F[now].flag = false;
            deal(p,F[now].b,F[now].a);
            deal(p,F[now].c,F[now].b);
            deal(p,F[now].a,F[now].c);
        }
    
        bool same(int s,int t)
        {
            Point &a = P[F[s].a];
            Point &b = P[F[s].b];
            Point &c = P[F[s].c];
            return fabs(volume(a,b,c,P[F[t].a])) < eps && fabs(volume(a,b,c,P[F[t].b])) < eps && fabs(volume(a,b,c,P[F[t].c])) < eps;
        }
    
        void create() //构建三维凸包
        {
            int i, j, tmp;
            face add;
            bool flag = true;
            num = 0;
            if(n < 4)
                return;
            for(i = 1; i < n; i++) //此段是为了保证前四个点不共面
            {
                if(getlen(P[0] - P[i]) > eps)
                {
                    swap(P[1], P[i]);
                    flag = false;
                    break;
                }
            }
            if(flag)
                return;
            flag = true;
            for(i = 2; i < n; i++) //使前三点不共线
            {
                if(getlen((P[0]-P[1]) ^ (P[1]-P[i])) > eps)
                {
                    swap(P[2], P[i]);
                    flag = false;
                    break;
                }
            }
            if(flag)
                return;
            flag = true;
            for(i = 3; i < n; i++) //使前四点不共面
            {
                if(fabs(((P[1]-P[0]) ^ (P[2]-P[0])) * (P[i]-P[0])) > eps)
                {
                    swap(P[3], P[i]);
                    flag = false;
                    break;
                }
            }
            if(flag)
                return;
            for(i = 0; i < 4; i++)
            {
                add.a = (i+1)%4;
                add.b = (i+2)%4;
                add.c = (i+3)%4;
                add.flag = true;
                if(dblcmp(P[i],add) > 0)
                    swap(add.b, add.c);
                g[add.a][add.b] = g[add.b][add.c] = g[add.c][add.a] = num;
                F[num++] = add;
            }
            for(i = 4; i < n; i++)
            {
                for(j = 0; j < num; j++)
                {
                    if(F[j].flag && dblcmp(P[i],F[j]) > eps)
                    {
                        dfs(i,j);
                        break;
                    }
                }
            }
            tmp = num;
            for(i = num = 0; i<tmp; i++)
                if(F[i].flag)
                {
                    F[num++] = F[i];
                }
        }
    
        double area() //表面积
        {
            double res = 0.0;
            if(n == 3)
            {
                Point p = cross(P[0],P[1],P[2]);
                res = getlen(p) / 2.0;
                return res;
            }
            for(int i = 0; i < num; i++)
                res += area(P[F[i].a],P[F[i].b],P[F[i].c]);
            return res/2.0;
        }
    
        double volume() //体积
        {
            double res = 0.0;
            Point tmp(0,0,0);
            for(int i = 0; i<num; i++)
                res += volume(tmp,P[F[i].a],P[F[i].b],P[F[i].c]);
            return fabs(res/6.0);
        }
    
        int triangle() //表面三角形个数
        {
            return num;
        }
    
        int polygon() //表面多边形个数
        {
            int i,j,res = 0,flag;
            for(i = 0; i < num; i++)
            {
                flag = 1;
                for(j = 0; j < i; j++)
                    if(same(i,j))
                    {
                        flag = 0;
                        break;
                    }
                res += flag;
            }
            return res;
        }
        Point getcenter()//求凸包质心
        {
            Point ans(0,0,0),temp = P[F[0].a];
            double v  =  0.0,t2;
            for(int i = 0; i < num; i++)
            {
                if(F[i].flag == true)
                {
                    Point p1 = P[F[i].a],p2 = P[F[i].b],p3 = P[F[i].c];
                    t2 = volume(temp,p1,p2,p3)/6.0;//体积大于0,也就是说,点 temp 不在这个面上
                    if(t2 > 0)
                    {
                        ans.x += (p1.x+p2.x+p3.x+temp.x)*t2;
                        ans.y += (p1.y+p2.y+p3.y+temp.y)*t2;
                        ans.z += (p1.z+p2.z+p3.z+temp.z)*t2;
                        v += t2;
                    }
                }
            }
            ans.x /= (4*v);
            ans.y /= (4*v);
            ans.z /= (4*v);
            return ans;
        }
        double function(Point pp) //点到凸包上的最近距离(枚举每个面到这个点的距离)
        {
            double min = INF;
            for(int i = 0; i<num; i++)
            {
                if(F[i].flag == true)
                {
                    Point p1 = P[F[i].a] , p2 = P[F[i].b] , p3 = P[F[i].c];
                    double a = ( (p2.y-p1.y)*(p3.z-p1.z)-(p2.z-p1.z)*(p3.y-p1.y) );
                    double b = ( (p2.z-p1.z)*(p3.x-p1.x)-(p2.x-p1.x)*(p3.z-p1.z) );
                    double c = ( (p2.x-p1.x)*(p3.y-p1.y)-(p2.y-p1.y)*(p3.x-p1.x) );
                    double d = ( 0-(a*p1.x+b*p1.y+c*p1.z) );
                    double temp = fabs(a*pp.x+b*pp.y+c*pp.z+d)/sqrt(a*a+b*b+c*c);
                    if(temp < min)min = temp;
                }
            }
            return min;
        }
    
    };
    CH3D hull;
    int main()
    {
        while(~scanf("%d", &hull.n))
        {
            for(int i = 0; i < hull.n; i++)
            {
                double x, y, z;
                scanf("%lf %lf %lf", &x, &y, &z);
                hull.P[i] = Point(x, y, z);
            }
            hull.create();
            printf("%d
    ", hull.polygon());
        }
        return 0;
    }
    View Code

    ·旋转卡壳

    求平面内的点之间的最长距离

    模板:

    bool cmp(Point a, Point b)
    {
        double tmp = xmul(p[0], a, b);
        if(sgn(tmp) > 0 || (sgn(tmp) == 0 && getdis(p[0], a) > getdis(p[0], b))) return true;
        return false;
    }
    int top;
    void graham()
    {
        int k = 0;
        top = 0;
        for(int i = 1; i < n; i++)
            if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i;
        swap(p[0], p[k]);
        sort(p+1, p+n, cmp);
        s[top++] = p[0]; s[top++] = p[1];
        for(int i = 2;i < n;i ++)
        {
            while(top > 1 && xmul(s[top-2], s[top-1], p[i]) < 0)
                top --;
            s[top++] = p[i];
        }
    }
    int RC()
    {
        s[top] = s[0];
        int now = 1, ans = 0;
        for(int i = 0; i < top; i++)
        {
            while(xmul(s[i], s[i+1], s[now]) < xmul(s[i], s[i+1], s[now+1]))
            {
                now++;
                if(now == top) now = 0;
            }
            ans = max(ans, max(getdis(s[now], s[i]), getdis(s[now], s[i+1])));
        }
        return ans;
    }
    View Code

    ·半平面交

    /*半平面相交(直线切割多边形)(点标号从1开始)*/  
    Point points[MAXN],p[MAXN],q[MAXN];  
    int n;  
    double r;  
    int cCnt,curCnt;  
    inline void getline(Point x,Point y,double &a,double &b,double &c){  
        a = y.y - x.y;  
        b = x.x - y.x;  
        c = y.x * x.y - x.x * y.y;  
    }  
    inline void initial(){  
        for(int i = 1; i <= n; ++i)p[i] = points[i];  
        p[n+1] = p[1];  
        p[0] = p[n];  
        cCnt = n;  
    }  
    inline Point intersect(Point x,Point y,double a,double b,double c){  
        double u = fabs(a * x.x + b * x.y + c);  
        double v = fabs(a * y.x + b * y.y + c);  
        return Point( (x.x * v + y.x * u) / (u + v) , (x.y * v + y.y * u) / (u + v) );  
    }  
    inline void cut(double a,double b ,double c){  
        curCnt = 0;  
        for(int i = 1; i <= cCnt; ++i){  
            if(a*p[i].x + b*p[i].y + c >= EPS)q[++curCnt] = p[i];  
            else {  
                if(a*p[i-1].x + b*p[i-1].y + c > EPS){  
                    q[++curCnt] = intersect(p[i],p[i-1],a,b,c);  
                }  
                if(a*p[i+1].x + b*p[i+1].y + c > EPS){  
                    q[++curCnt] = intersect(p[i],p[i+1],a,b,c);  
                }  
            }  
        }  
        for(int i = 1; i <= curCnt; ++i)p[i] = q[i];  
        p[curCnt+1] = q[1];p[0] = p[curCnt];  
        cCnt = curCnt;  
    }  
    inline void solve(){  
        //注意:默认点是顺时针,如果题目不是顺时针,规整化方向  
        initial();  
        for(int i = 1; i <= n; ++i){  
            double a,b,c;  
            getline(points[i],points[i+1],a,b,c);  
            cut(a,b,c);  
        }  
        /* 
        如果要向内推进r,用该部分代替上个函数 
        for(int i = 1; i <= n; ++i){ 
            Point ta, tb, tt; 
            tt.x = points[i+1].y - points[i].y; 
            tt.y = points[i].x - points[i+1].x; 
            double k = r / sqrt(tt.x * tt.x + tt.y * tt.y); 
            tt.x = tt.x * k; 
            tt.y = tt.y * k; 
            ta.x = points[i].x + tt.x; 
            ta.y = points[i].y + tt.y; 
            tb.x = points[i+1].x + tt.x; 
            tb.y = points[i+1].y + tt.y; 
            double a,b,c; 
            getline(ta,tb,a,b,c); 
            cut(a,b,c); 
        } 
        */  
        //多边形核的面积  
        double area = 0;  
        for(int i = 1; i <= curCnt; ++i)  
            area += p[i].x * p[i + 1].y - p[i + 1].x * p[i].y;  
        area = fabs(area / 2.0);  
        //此时cCnt为最终切割得到的多边形的顶点数,p为存放顶点的数组  
    }  
    inline void GuiZhengHua(){  
         //规整化方向,逆时针变顺时针,顺时针变逆时针  
        for(int i = 1; i < (n+1)/2; i ++)  
          swap(points[i], points[n-i]);//头文件加iostream  
    }  
    inline void init(){  
         for(int i = 1; i <= n; ++i)points[i].input();  
            points[n+1] = points[1];  
    }
    View Code

    裸题:POJ 2187

    求n个点之间的最长距离的平方

      1 #include <iostream>
      2 #include <iostream>
      3 #include <cstdio>
      4 #include <cstring>
      5 #include <cmath>
      6 #include <algorithm>
      7 #include <queue>
      8 using namespace std;
      9 const int SZ = 50200;
     10 const int INF = 1e9+10;
     11 const double eps = 1e-8;
     12 const double pi = acos(-1.0);
     13 using namespace std;
     14 int sgn(double x)
     15 {
     16     if(fabs(x) < eps) return 0;
     17     if(x < 0) return -1;
     18     return 1;
     19 }
     20 struct Point
     21 {
     22     double x, y;
     23     Point () {}
     24     Point (double x, double y) : x(x), y(y) {}
     25     Point operator +(const Point &a)const{
     26         return (Point){x + a.x, y + a.y};
     27     }
     28     Point operator -(const Point &a)const{
     29         return (Point){x - a.x, y - a.y};
     30     }
     31     bool operator ==(const Point &a)const{
     32         if(sgn(x - a.x) == 0 && sgn(y - a.y) == 0) return true;
     33         return false;
     34     }
     35     bool operator !=(const Point &a)const{
     36         return x != a.x || y != a.y;
     37     }
     38     bool operator <(const Point &a)const{
     39         if(a.x != x) return x < a.x;//以x作为第一关键字排序
     40         return y < a.y;
     41     }
     42     double operator *(const Point &a)const{//点乘
     43         return x * a.x + y * a.y;
     44     }
     45     double operator ^(const Point &a)const{//叉乘
     46         return x * a.y - y * a.x;
     47     }
     48 }p[SZ], s[SZ];
     49 double xmul(Point a, Point b, Point c) //ab * ac, xmul<0表示p0在se左
     50 {
     51     return (b - a) ^ (c - a);
     52 }
     53 int getdis(Point a, Point b)//点a与点b之间的距离
     54 {
     55     return (a-b) * (a-b);
     56 }
     57 int n;
     58 bool cmp(Point a, Point b)
     59 {
     60     double tmp = xmul(p[0], a, b);
     61     if(sgn(tmp) > 0 || (sgn(tmp) == 0 && getdis(p[0], a) > getdis(p[0], b))) return true;
     62     return false;
     63 }
     64 int top;
     65 void graham()
     66 {
     67     int k = 0;
     68     top = 0;
     69     for(int i = 1; i < n; i++)
     70         if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i;
     71     swap(p[0], p[k]);
     72     sort(p+1, p+n, cmp);
     73     s[top++] = p[0]; s[top++] = p[1];
     74     for(int i = 2;i < n;i ++)
     75     {
     76         while(top > 1 && xmul(s[top-2], s[top-1], p[i]) < 0)
     77             top --;
     78         s[top++] = p[i];
     79     }
     80 }
     81 int RC()
     82 {
     83     s[top] = s[0];
     84     int now = 1, ans = 0;
     85     for(int i = 0; i < top; i++)
     86     {
     87         while(xmul(s[i], s[i+1], s[now]) < xmul(s[i], s[i+1], s[now+1]))
     88         {
     89             now++;
     90             if(now == top) now = 0;
     91         }
     92         ans = max(ans, max(getdis(s[now], s[i]), getdis(s[now], s[i+1])));
     93     }
     94     return ans;
     95 }
     96 int main()
     97 {
     98     scanf("%d", &n);
     99     for(int i = 0; i < n; i++)
    100     {
    101         double x, y;
    102         scanf("%lf %lf", &x, &y);
    103         p[i] = Point(x, y);
    104     }
    105     graham();
    106     printf("%d
    ", RC());
    107     return 0;
    108 }
    View Code

    ·半平面交

    模板:

     1 /*半平面相交(直线切割多边形)(点标号从1开始)*/
     2 Point points[SZ],p[SZ],q[SZ];
     3 int n;
     4 double r;
     5 int cCnt,curCnt;
     6 inline void getline(Point x,Point y,double &a,double &b,double &c)
     7 {
     8     a = y.y - x.y;
     9     b = x.x - y.x;
    10     c = y.x * x.y - x.x * y.y;
    11 }
    12 inline void initial()
    13 {
    14     for(int i = 1; i <= n; ++i) p[i] = points[i];
    15     p[n+1] = p[1];
    16     p[0] = p[n];
    17     cCnt = n;
    18 }
    19 inline Point intersect(Point x,Point y,double a,double b,double c)
    20 {
    21     double u = fabs(a * x.x + b * x.y + c);
    22     double v = fabs(a * y.x + b * y.y + c);
    23     return Point( (x.x * v + y.x * u) / (u + v) , (x.y * v + y.y * u) / (u + v) );
    24 }
    25 inline void cut(double a,double b ,double c)
    26 {
    27     curCnt = 0;
    28     for(int i = 1; i <= cCnt; ++i)
    29     {
    30         if(a*p[i].x + b*p[i].y + c >= eps)q[++curCnt] = p[i];
    31         else
    32         {
    33             if(a*p[i-1].x + b*p[i-1].y + c > eps)
    34             {
    35                 q[++curCnt] = intersect(p[i],p[i-1],a,b,c);
    36             }
    37             if(a*p[i+1].x + b*p[i+1].y + c > eps)
    38             {
    39                 q[++curCnt] = intersect(p[i],p[i+1],a,b,c);
    40             }
    41         }
    42     }
    43     for(int i = 1; i <= curCnt; ++i)p[i] = q[i];
    44     p[curCnt+1] = q[1];
    45     p[0] = p[curCnt];
    46     cCnt = curCnt;
    47 }
    48 inline void solve()
    49 {
    50     //注意:默认点是顺时针,如果题目不是顺时针,规整化方向
    51     initial();
    52     for(int i = 1; i <= n; ++i)
    53     {
    54         double a,b,c;
    55         getline(points[i],points[i+1],a,b,c);
    56         cut(a,b,c);
    57     }
    58     /*
    59     如果要向内推进r,用该部分代替上个函数
    60     for(int i = 1; i <= n; ++i){
    61         Point ta, tb, tt;
    62         tt.x = points[i+1].y - points[i].y;
    63         tt.y = points[i].x - points[i+1].x;
    64         double k = r / sqrt(tt.x * tt.x + tt.y * tt.y);
    65         tt.x = tt.x * k;
    66         tt.y = tt.y * k;
    67         ta.x = points[i].x + tt.x;
    68         ta.y = points[i].y + tt.y;
    69         tb.x = points[i+1].x + tt.x;
    70         tb.y = points[i+1].y + tt.y;
    71         double a,b,c;
    72         getline(ta,tb,a,b,c);
    73         cut(a,b,c);
    74     }
    75     */
    76     //多边形核的面积
    77     double area = 0;
    78     for(int i = 1; i <= curCnt; ++i)
    79         area += p[i].x * p[i + 1].y - p[i + 1].x * p[i].y;
    80     area = fabs(area / 2.0);
    81     //此时cCnt为最终切割得到的多边形的顶点数,p为存放顶点的数组
    82 }
    83 inline void GuiZhengHua()
    84 {
    85     //规整化方向,逆时针变顺时针,顺时针变逆时针
    86     for(int i = 1; i < (n+1)/2; i ++)
    87         swap(points[i], points[n-i]);//头文件加iostream
    88 }
    89 inline void init()
    90 {
    91     scanf("%d", &n);
    92     for(int i = 1; i <= n; ++i)
    93     {
    94         double x, y;
    95         scanf("%lf %lf", &x, &y);
    96         points[i] = Point(x, y);
    97     }
    98     points[n+1] = points[1];
    99 }
    View Code

    ·圆交多边形

    模板:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    using namespace std;
    const int SZ = 520;
    const int INF = 1e9+10;
    const double eps = 1e-8;
    const double pi = acos(-1.0);
    int n;
    int sgn(double x)
    {
        if(fabs(x) < eps) return 0;
        if(x < 0) return -1;
        return 1;
    }
    struct Point
    {
        double x, y;
        Point () {}
        Point (double x, double y) : x(x), y(y) {}
        Point operator +(const Point &a)const{
            return Point(x + a.x, y + a.y);
        }
        Point operator -(const Point &a)const{
            return Point(x - a.x, y - a.y);
        }
        bool operator ==(const Point &a)const{
            if(sgn(x - a.x) == 0 && sgn(y - a.y) == 0) return true;
            return false;
        }
        bool operator !=(const Point &a)const{
            return x != a.x || y != a.y;
        }
        bool operator <(const Point &a)const{
            if(a.x != x) return x < a.x;//以x作为第一关键字排序
            return y < a.y;
        }
        double operator *(const Point &a)const{//点乘
            return x * a.x + y * a.y;
        }
        double operator ^(const Point &a)const{//叉乘
            return x * a.y - y * a.x;
        }
        double sqrx() //向量的模
        {
            return sqrt(x*x+y*y);
        }
    }p[SZ], A, B;
    double xmult(Point a, Point b, Point c) //ab * ac, xmul<0表示p0在se左
    {
        return (b - a) ^ (c - a);
    }
    double getsqrtdis(Point a, Point b)//点a与点b之间的距离
    {
        return sqrt((a-b) * (a-b));
    }
    double getdis(Point a, Point b)
    {
        return (a-b) * (a-b);
    }
    Point crossline(Point u1, Point v1, Point u2, Point v2)//直线u1v1与直线u2v2的交点
    {
        double a1 = (v2 - u2) ^ (u1 - u2);
        double a2 = (v2 - u2) ^ (v1 - u2);
        return Point( (u1.x*a2 - v1.x*a1) / (a2 - a1), (u1.y*a2 - v1.y*a1) / (a2 - a1) );
    }
    void intersection_line_circle(Point c,double r,Point l1,Point l2,Point& p1,Point& p2){
        Point p=c;
        double t;
        p.x+=l1.y-l2.y;
        p.y+=l2.x-l1.x;
        p=crossline(p,c,l1,l2);
        t=sqrt(r*r-getsqrtdis(p,c)*getsqrtdis(p,c))/getsqrtdis(l1,l2);
        p1.x=p.x+(l2.x-l1.x)*t;
        p1.y=p.y+(l2.y-l1.y)*t;
        p2.x=p.x-(l2.x-l1.x)*t;
        p2.y=p.y-(l2.y-l1.y)*t;
    }
    Point ptoseg(Point p,Point l1,Point l2)            //点到线段的最近距离
    {
        Point t=p;
        t.x+=l1.y-l2.y,t.y+=l2.x-l1.x;
        if (xmult(l1,t,p)*xmult(l2,t,p)>eps)
        return getsqrtdis(p,l1)<getsqrtdis(p,l2)?l1:l2;
        return crossline(p,t,l1,l2);
    }
    struct Circle
    {
        Point c;
        double r;
        Circle() {}
        Circle(Point c, double r) : c(c), r(r) {}
    }C;
     double Triangle_Circle_Area(Point a,Point b,Point o,double r)
    {
        double sign=1.0;
        a=a-o;
        b=b-o;
        o=Point(0.0,0.0);
        if(fabs(xmult(a,b,o))<eps) return 0.0;
        if(getdis(a,o)>getdis(b,o))
        {
            swap(a,b);
            sign=-1.0;
        }
        if(getdis(a,o)<r*r+eps)
        {
            if(getdis(b,o)<r*r+eps) return xmult(a,b,o)/2.0*sign;
            Point p1,p2;
            intersection_line_circle(o,r,a,b,p1,p2);
            if(getsqrtdis(p1,b)>getsqrtdis(p2,b)) swap(p1,p2);
            double ret1=fabs(xmult(a,p1,o));
            double ret2=acos( p1*b/p1.sqrx()/b.sqrx() )*r*r;
            double ret=(ret1+ret2)/2.0;
            if(xmult(a,b,o)<eps && sign>0.0 || xmult(a,b,o)>eps && sign<0.0) ret=-ret;
            return ret;
        }
        Point ins=ptoseg(o,a,b);
        if(getdis(o,ins)>r*r-eps)
        {
            double ret=acos( a*b/a.sqrx()/b.sqrx() )*r*r/2.0;
            if(xmult(a,b,o)<eps && sign>0.0 || xmult(a,b,o)>eps && sign<0.0) ret=-ret;
            return ret;
        }
        Point p1,p2;
        intersection_line_circle(o,r,a,b,p1,p2);
        double cm=r/(getsqrtdis(o,a)-r);
        Point m=Point( (o.x+cm*a.x)/(1+cm) , (o.y+cm*a.y)/(1+cm) );
        double cn=r/(getsqrtdis(o,b)-r);
        Point n=Point( (o.x+cn*b.x)/(1+cn) , (o.y+cn*b.y)/(1+cn) );
        double ret1 = acos( m*n/m.sqrx()/n.sqrx() )*r*r;
        double ret2 = acos( p1*p2/p1.sqrx()/p2.sqrx() )*r*r-fabs(xmult(p1,p2,o));
        double ret=(ret1-ret2)/2.0;
        if(xmult(a,b,o)<eps && sign>0.0 || xmult(a,b,o)>eps && sign<0.0) ret=-ret;
        return ret;
    }
    
    int main()
    {
        double k;
        int tt = 0;
        while(~scanf("%d %lf", &n, &k))
        {
            double x, y;
            for(int i = 1; i <= n; i++)
            {
                scanf("%lf %lf", &x, &y);
                p[i] = Point(x, y);
            }
            scanf("%lf %lf", &x, &y);
            A = Point(x, y);
            scanf("%lf %lf", &x, &y);
            B = Point(x, y);
            double D = (2*k*k*A.x - 2*B.x) / (1 - k*k);
            double E = (2*k*k*A.y - 2*B.y) / (1 - k*k);
            double F = (B.x*B.x + B.y*B.y - k*k*A.x*A.x - k*k*A.y*A.y) / (1 - k*k);
            C = Circle(Point(-D/2, -E/2), sqrt(D*D/4 + E*E/4 - F) );
            double ans = 0.0;
            p[n+1] = p[1];
            for(int i = 1; i <= n; i++)
                ans += Triangle_Circle_Area(p[i], p[i+1], C.c, C.r);
            printf("Case %d: %.10f
    ", ++tt, fabs(ans));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    JSON Web令牌(JWT)
    CSRF跨站点请求伪造(Cross—Site Request Forgery)
    logging模块
    Django中使用Celery
    第一坑 先引入jQuery ./引入
    CSS 入门
    超大型文件传输方案 + socket + subprocess popen 远程执行系统命令
    MYSQL的执行计划 事务处理 和 跑路
    mysql 存储过程
    Django中CBV View的as_view()源码解析
  • 原文地址:https://www.cnblogs.com/pinkglightning/p/9515008.html
Copyright © 2011-2022 走看看