zoukankan      html  css  js  c++  java
  • 计算几何模板(一)

    这两周一直在做计算几何的题,感觉计算几何题就是读懂题意,并且能有清晰的解题思路,剩下的就是套用模板了,所以模板相当重要!下面整理了一些模板以便以后做题用

    说明:下面的eps 都是1e-8;

    目录:

    ㈠ Pick定理:

    ㈡ 在二维空间中,已知四个点的坐标,求交点的坐标

    ㈢ 已知多边形的顶点的坐标,求多边形的面积利用叉积

    ㈣ 求三角形面积

    ㈤ 判断一个多边形是否是一个凸包

    ㈥ 求凸包的周长(在若干个点钟选取点组成凸包并求其周长)

    ㈦ 判断点是否在凸包内

    ㈧ 凸包内的点到凸包每条边的距离

    ㈨ 跨立试验--判断两条线段是否相交(含顶点)

    ㈩ 判断点是否在矩形的内部

    ①.Pick定理:如图给定顶点坐标都是整点,所围成的多边形的面积area、多边形边上的点的个数on以及多边形内部点的个数in满足area = in + on / 2 – 1;

    POJ 1265 Area

    代码如下:

    View Code
    int m, n, on, in;
    double area;
    struct node
    {
        int x, y;
    }point[MAX];
    int Gcd(int a, int b)//求a和b的最大公约数的函数
    {
        int temp;
        if (a < b)//把a和b中较大的数字放到a中
        {
            temp = a;
            a = b;
            b = temp;
        }
        if (b == 0)//找到两者的最大公约数,直接返回a
        {
            return a;
        }
        return Gcd(b, a % b);//否则继续往下找
    }
    int Area(int i)//叉积计算多边形的面积
    {
        return double(point[i - 1].x * point[i].y - point[i].x * point[i - 1].y);
    }
    int main()
    {
        int i, j, xx, yy;
        scanf("%d", &m);
        for (i = 1; i <= m; ++i)
        {
            printf("Scenario #%d:\n", i);
            scanf("%d", &n);
            memset(point, 0, sizeof(point));
            on = 0;
            in = 0;
            area = 0;
            for (j = 1; j <= n; ++j)
            {
                scanf("%d%d", &xx, &yy);
                point[j].x = xx + point[j - 1].x;
                point[j].y = yy + point[j - 1].y;
                on += Gcd(abs(xx), abs(yy));//求在边上的点的个数
                area += Area(j);
            }
            area = area / 2.0;
            in = int(area) + 1 - on / 2;
            printf("%d %d %.1lf\n", in, on, area);
            printf("\n");
        }
        return 0;
    }

    ②在二维空间中,已知四个点的坐标,求交点的坐标

    核心代码如下:

    Point GetPoint(Point p1, Point p2, Point p3, Point p4)//已知四个点求直线相交的点的坐标
    //(这种求法包括了直线斜率不存在或为0的情况下)
    {
        Point p0;//p0就是所求的交点的坐标
        double A1 = p2.y - p1.y;
        double B1 = p1.x - p2.x;
        double C1 = p1.y * (-B1) - p1.x * A1;
        double A2 = p4.y - p3.y;
        double B2 = p3.x - p4.x;
        double C2 = p3.y *(-B2) - p3.x * A2;
        p0.x = (C2 * B1 - C1 * B2) / (A1 * B2 - A2 * B1);
        p0.y = (C2 * A1 - C1 * A2) / (B1 * A2 - B2 * A1);
        return p0;
    }

    ③已知多边形的顶点的坐标,求多边形的面积利用叉积

    核心代码实现如下:

    for (int i = 0; i < N; ++i)
    {
    int j = (i + 1) % N;
    area += point[i].x * point[j].y - point[i].y * point[j].x;
    }
    area = area / 2;
    if (area < 0)
    {
    area = - area;
    }

    ④求三角形的面积

    ⑴   利用的是海伦公式求的三角形面积(已知三角形的三个顶点的坐标)

    原理假设有一个三角形,边长分别为a、b、c,三角形的面积Area可由以下公式求得:设p是周长的一半,p=(a+b+c)/2,则三角形的面积为:Area =sqrt〔p*(p-a)*(p-b)*(p-c)〕

    代码如下:

    double GetArea(int m, Point tr[])
    {
        double a[m];
        double pp = 0;
        for (int i = 0; i < m; ++i)
        {
            a[i] = Dis(tr[i], tr[(i + 1) % m]);
            pp += a[i];
        }
        pp = pp / 2.0;
        return sqrt(pp * (pp - a[0]) * (pp - a[1]) * (pp -a[2]));
    }
    ⑵   利用叉积求三角形面积(已知三角形的三个顶点的坐标)

    代码如下:

    double GetArea(int m, Point tr[])//其中这儿的m就是3了
    {
        int i;
        double area = tr[0].y * (tr[m - 1].x - tr[1].x);
        for (i = 1; i < m; ++i)//求三角形的面积
        {
            area += tr[i].y * (tr[i - 1].x - tr[(i + 1) % m].x);
        }
        if (area < 0)
        {
            area = -area;
        }
        return area = area / 2.0;
    }

    ⑤判断一个多边形是否是一个凸包(有若干个点是否能构成凸包)

    核心代码如下:

    for (i = 0; i + 2 < n; ++i)
    {
         dis = Multi(p[i + 1], p[i + 2], p[i]);
         if (abs(dis) >= eps)//先确定多边形的输入是逆时针还是顺时针
         {
               break;
          }
    }
    flag = 1;
    for (i = 0; i < n && flag; ++i)
    {
        for (j = 0, k = i + 2; j < n - 2; j ++, k ++)
        {
             double q = Multi(p[(i + 1) % n], p[k % n], p[i]);
             if (q * dis < -eps)//出现了旋转方向相反的点了
             {
                  flag = 0;
                     break;
            }
        }
     }
     if (flag == 0)//不是凸包
    {
          printf("不是凸包\n");
     }

    ⑥求凸包的周长(在若干个点钟选取点组成凸包并求其周长)

    核心代码如下:

    int convex[MAX];//储存选取的点
    bool cmp(Point a, Point b)//先按y的从小到大排序,若y的大小相等的时候,再按x从小到大排序!这个函数在#include<algorithm>头文件中
    {
        if(a.y == b.y) return a.x < b.x;
        return a.y < b.y;
    }
    double Multi(Point p1, Point p2, Point p3)
    {
       return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y);
    }
    void Graham()//选取点构成凸包
    {
        int i, count;
        top = 1;
        sort(p, p + N, cmp);//排序函数
        for (i = 0; i < 3; ++i)//先把前三个点压入栈中
        {
            convex[i] = i;
        }
        for (i = 2; i < N; ++i)
        {
            while (top && Multi(p[i], p[convex[top]], p[convex[top - 1]]) >= 0)
            {
                top --;
            }
            convex[++ top] = i;
        }
        count = top;
        convex[++ top] = N - 2;
        for (i = N - 3; i >= 0; --i)
        {
            while (top != count && Multi(p[i], p[convex[top]], p[convex[top - 1]]) >= 0)
            {
                top --;
            }
            convex[++ top] = i;
        }
    }
    for (i = 0; i < top; ++i)//求周长
    {
          ans += Dis(convex[i], convex[(i + 1) % top]);
    }
     printf("%.0lf\n", ans);

    ⑦判断点是否在凸包内

    int Judge()
    {
        double a, b;
        int i;
        Point p3;
        p3.x = x;
        p3.y = y;
        b = Multi(p[0], p[1], p3);
        for (i = 1; i < n; ++i)
        {
            a = Multi(p[i], p[(i + 1) % n], p3);
            if (a * b < - eps)
            {
                return 1;//说明点(x, y)不在凸包内
            }
            b = a;
        }
        return 0;
    }

    ⑧凸包内的点到凸包每条边的距离

    实现的原理是:求到多边形每条边的距离利用了三角形的面积 = (底边的边长 * 高) / 2;即 dis = 2.0 * area / h;

    triangle[0].x = x;
    triangle[0].y = y;//(x, y)是凸包内的一个点
    for (i = 0; i < n; ++i)
    {
         triangle[1] = p[i];
         triangle[2] = p[(i + 1) % n];
         dis = 2.0 * GetArea(3, triangle) / Dis(triangle[1], triangle[2]);
         printf("%.2lf\n", dis);
    }

    ⑨跨立试验--判断两条线段是否相交(含顶点)

    bool Isintersect(Point a1, Point a2, Point b1, Point b2)//判断两条线段是否相交(含顶点)
    {
        if (Min(a1.x, a2.x) <= Max(b1.x, b2.x) &&
            Min(a1.y, a2.y) <= Max(b1.y, b2.y) &&
            Min(b1.x, b2.x) <= Max(a1.x, a2.x) &&
            Min(b1.y, b2.y) <= Max(a1.y, a2.y) &&
            Multi(a1, a2, b1) * Multi(a1, a2, b2) <= 0 &&
            Multi(b1, b2, a1) * Multi(b1, b2, a2) <= 0
            )
            return true;//说明两线段之间相交
        return false;
    }

    ⑩判断点是否在矩形的内部

    其中seg是代表点,rec[1],rec[3]代表了矩形的对角点
    bool Inrectangle(int i)//判断点是否在矩形的内部
    {
        if (seg[i].x > Max(rec[1].x, rec[3].x)) return false;
        if (seg[i].y > Max(rec[1].y, rec[3].y)) return false;
        if (seg[i].x < Min(rec[1].x, rec[3].x)) return false;
        if (seg[i].y < Min(rec[1].y, rec[3].y)) return false;
        //如果满足上面的,说明线段在矩形的内部并且没有和矩形没有交点(含线段的顶点)
        return true;
    }
    ⑾    已知两条相交直线,知道每条直线的的两个点,求交点的坐标
    Point GetPoint(Point p1, Point p2, Point p3, Point p4)//已知四个点求直线相交的点的坐标
    //(这种求法包括了直线斜率不存在或为0的情况下)
    {
        Point p0;
        double A1 = p2.y - p1.y;
        double B1 = p1.x - p2.x;
        double C1 = p1.y * (-B1) - p1.x * A1;
        double A2 = p4.y - p3.y;
        double B2 = p3.x - p4.x;
        double C2 = p3.y *(-B2) - p3.x * A2;
        p0.x = (C2 * B1 - C1 * B2) / (A1 * B2 - A2 * B1);
        p0.y = (C2 * A1 - C1 * A2) / (B1 * A2 - B2 * A1);
        return p0;
    }
  • 相关阅读:
    Educational Codeforces Round 88 (Rated for Div. 2) D. Yet Another Yet Another Task(枚举/最大连续子序列)
    Educational Codeforces Round 88 (Rated for Div. 2) A. Berland Poker(数学)
    Educational Codeforces Round 88 (Rated for Div. 2) E. Modular Stability(数论)
    Educational Codeforces Round 88 (Rated for Div. 2) C. Mixing Water(数学/二分)
    Codeforces Round #644 (Div. 3)
    Educational Codeforces Round 76 (Rated for Div. 2)
    Educational Codeforces Round 77 (Rated for Div. 2)
    Educational Codeforces Round 87 (Rated for Div. 2)
    AtCoder Beginner Contest 168
    Codeforces Round #643 (Div. 2)
  • 原文地址:https://www.cnblogs.com/lidaojian/p/2492678.html
Copyright © 2011-2022 走看看