计算几何模板(一)

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

说明:下面的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;
}
原文地址:https://www.cnblogs.com/lidaojian/p/2492678.html